I need to get the table row index during a contextMenuEvent in pyQt5, but I keep getting odd row offsets. Since this is my first pyQt project, I'm quite lost. I have the following code.
def contextMenuEvent(self, event):
menu = QMenu(self)
openAction = menu.addAction('Open in browser')
action = menu.exec_(event.globalPos())
if action == openAction:
row = self.tableWidget.rowAt(event.y()) # Should this be event.globalY?
self.so_something(row)
Edit: adding code sample. You can see that when the execution gets to the event produced when right-clicking on a row, the printed number is not the correct row number. Usually it has an offset, and last rows produce -1.
import sys
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QLabel, QLineEdit, QWidget, \
QPushButton, QVBoxLayout, QHBoxLayout, QComboBox, \
QTableWidget, QHeaderView, QTableWidgetItem, \
QMenu, QApplication
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# Window size and title
self.setWindowTitle('Test')
self.resize(700, 700)
self.setMinimumWidth(700)
# Label
addressLabel = QLabel('Testing')
addressLabel.setAlignment(Qt.AlignCenter)
# Dropdown
self.addressDropdown = QComboBox(self)
self.addressDropdown.addItem('A')
self.addressDropdown.addItem('B')
# Refresh button
refreshButton = QPushButton()
refreshButton.setMaximumSize(40, 40)
# Address layout
addressayout = QHBoxLayout()
addressayout.addWidget(addressLabel, 1)
addressayout.addWidget(self.addressDropdown, 7)
addressayout.addWidget(refreshButton)
# Balance label
balaceLabel = QLabel()
balaceLabel.setText('Testing')
balaceLabel.setAlignment(Qt.AlignCenter)
# Balance amount label
self.balaceAmountLabel = QLabel()
self.balaceAmountLabel.setText('Testing')
self.balaceAmountLabel.setAlignment(Qt.AlignCenter)
# Balance layout
balanceLayout = QVBoxLayout()
balanceLayout.addWidget(balaceLabel)
balanceLayout.addWidget(self.balaceAmountLabel)
# Transactions label
transactionsLabel = QLabel('Testing')
transactionsLabel.setAlignment(Qt.AlignCenter)
# Transactions table
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(10)
self.tableWidget.setColumnCount(1)
self.tableWidget.verticalHeader().setVisible(False)
self.tableWidget.horizontalHeader().setVisible(False)
self.tableWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
item = QTableWidgetItem('Testing')
item.setTextAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
self.tableWidget.setItem(0, 0, item)
# Transactions layout
transactionsLayout = QVBoxLayout()
transactionsLayout.addWidget(transactionsLabel)
transactionsLayout.addWidget(self.tableWidget)
# Send label A
sendLabelA = QLabel('Send')
sendLabelA.setAlignment(Qt.AlignCenter)
# Send amount
self.sendAmount = QLineEdit()
self.sendAmount.setAlignment(Qt.AlignCenter)
# Send label B
sendLabelB = QLabel('to')
sendLabelB.setAlignment(Qt.AlignCenter)
# Send address
self.sendAddress = QLineEdit()
self.sendAddress.setAlignment(Qt.AlignCenter)
# Send button
sendButton = QPushButton()
sendButton.setMaximumSize(40, 40)
sendIcon = QIcon.fromTheme("mail-send")
sendButton.setIcon(sendIcon)
sendButton.setIconSize(QSize(24,24))
# Send layout
sendLayout = QHBoxLayout()
sendLayout.addWidget(sendLabelA)
sendLayout.addWidget(self.sendAmount, 2)
sendLayout.addWidget(sendLabelB)
sendLayout.addWidget(self.sendAddress, 4)
sendLayout.addWidget(sendButton)
# Window layout
layout = QVBoxLayout()
layout.addLayout(addressayout)
layout.addLayout(balanceLayout)
layout.addLayout(transactionsLayout)
layout.addLayout(sendLayout)
self.setLayout(layout)
def contextMenuEvent(self, event):
menu = QMenu(self)
openAction = menu.addAction('Open in browser')
action = menu.exec_(event.globalPos())
row = self.tableWidget.rowAt(event.y())
if action == openAction:
print(row)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The coordinate that rowAt() method requires must be with respect to the viewport of the QTableWidget so you must convert the global position to local using mapFromGlobal() method:
def contextMenuEvent(self, event):
gp = event.globalPos()
menu = QMenu(self)
openAction = menu.addAction("Open in browser")
action = menu.exec_(gp)
vp_pos = self.tableWidget.viewport().mapFromGlobal(gp)
row = self.tableWidget.rowAt(vp_pos.y())
if action == openAction:
print(row)
Related
My code is supposed to add data to a two column table when "add" button is clicked. The problem is that when the "add" button is clicked, only the empty row is being added. Can someone please let me know what is wrong? Below is the part of the code that adds data1 and data2 to a table on the right side of the layout. The function add_entry is where the data is being added.
# Import dependencies
from PyQt5.QtWidgets import (QWidget, QApplication, QTableWidget, QTableWidgetItem,QHBoxLayout, QVBoxLayout, QHeaderView, QPushButton, QDialog,
QLabel, QFileDialog, QMainWindow, QAction, QLineEdit)
from PyQt5.Qt import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtChart import QChart, QChartView, QLineSeries
import sys
import pandas as pd
import math
# ------------------------------------------------------UI-main----------------------------------------------------------------------------------
# Creates a QApplication instance
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.items=0
# Creates table on the left size
self.table_l = QTableWidget()
self.table_l.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# Creates layout object for the right side
self.layoutRight = QVBoxLayout()
# Creates chart widget
self.chartView = QChartView()
# Smooths the edge of the chart
self.chartView.setRenderHint(QPainter.Antialiasing)
# Creates table on the right size
self.table_r = QTableWidget()
self.table_r.setColumnCount(2)
# self.table_r.setRowCount()
self.table_r.setHorizontalHeaderLabels(('Data1', 'Data2'))
self.table_r.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.table_r.setMaximumSize(600, 300)
self.lineEditData1 = QLineEdit()
self.lineEditData2 = QLineEdit()
# Create push buttons
self.buttonAdd = QPushButton('Add')
self.buttonClear = QPushButton('Clear')
self.buttonQuit = QPushButton('Quit')
self.buttonAdd.setEnabled(False)
self.layoutRight.setSpacing(10)
self.layoutRight.addWidget(self.table_r, 50)
self.layoutRight.addWidget(QLabel('data1'))
self.layoutRight.addWidget(self.lineEditData1)
self.layoutRight.addWidget(QLabel('data2'))
self.layoutRight.addWidget(self.lineEditData2)
self.layoutRight.addWidget(self.buttonAdd)
self.layout = QHBoxLayout()
self.layout.addWidget(self.table_l, 50)
self.setLayout(self.layout)
self.layout.addLayout(self.layoutRight, 50)
# Connect button to function functions
self.buttonQuit.clicked.connect(lambda:app.quit())
self.buttonAdd.clicked.connect(self.add_entry)
self.buttonClear.clicked.connect(self.reset_table)
self.lineEditData1.textChanged[str].connect(self.check_disable)
self.lineEditData2.textChanged[str].connect(self.check_disable)
def add_entry(self):
Data1 = self.lineEditData1.text()
Data2 = self.lineEditData2.text()
try:
Data1Item = QTableWidgetItem(int(Data1))
Data2Item = QTableWidgetItem(float(Data2))
Data2Item.setTextAlignment(Qt.AlignRight | Qt.AlignCenter)
self.table_r.insertRow(self.items)
self.table_r.setItem(self.items, 0, Data1Item)
self.table_r.setItem(self.items, 1, Data2Item)
self.items +=1
# after passing the item, clear the field by entering an empty string
self.lineEditData1.setText('')
self.lineEditData2.setText('')
except ValueError:
pass
# Creates main window object instance
class MainWindow(QMainWindow):
def __init__(self, widget):
super().__init__()
self.setWindowTitle('test')
self.resize(1200, 1200)
self.menuBar = self.menuBar()
self.fileMenu = self.menuBar.addMenu('File')
# import wind speed data
importAction = QAction('Open File', self)
importAction.setShortcut('Ctrl+O')
# exit action
exitAction = QAction('Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(lambda: app.quit())
self.fileMenu.addAction(importAction)
self.fileMenu.addAction(exitAction)
self.setCentralWidget(widget)
if __name__ =='__main__':
# don't auto scale when drag app to a different monitor
#QGuiApplication.setHightDpiScaleFactorRoundingPolicy(Qt.HightDpiScaleFactorRoundingPolicy.PassThrough)
app = QApplication(sys.argv)
w = MyApp()
demo = MainWindow(w)
demo.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing window...')
The objective of exceptions is not to hide errors but to know how to prevent them, so they must be as small as possible so as not to hide other errors. In this case, QTableWidgetItem accepts a string as an argument and not numerical values, therefore an exception is thrown preventing the code that adds the items from being executed. The solution is to use the setData() method of the QTableWidgetItem:
def add_entry(self):
data1 = self.lineEditData1.text()
data2 = self.lineEditData2.text()
try:
value1 = int(data1)
value2 = float(data2)
except ValueError:
print("failed conversion")
return
else:
data1_item = QTableWidgetItem()
data1_item.setData(Qt.DisplayRole, value1)
data2_item = QTableWidgetItem()
data2_item.setData(Qt.DisplayRole, value2)
data2_item.setTextAlignment(Qt.AlignRight | Qt.AlignCenter)
row = self.table_r.rowCount()
self.table_r.insertRow(row)
self.table_r.setItem(row, 0, data1_item)
self.table_r.setItem(row, 1, data2_item)
self.lineEditData1.clear()
self.lineEditData2.clear()
Here is a picture of my GUI:
I want to display all 100 items in my list widget without an inner scroll bar (there is an outer scroll bar, so there is no issue that I cannot fit all the items).
I have tried disabling the scroll bar for the list widget, but that didn't increase the number of items the list widget was displaying.
Here is my code:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
if __name__ == "__main__":
app = QApplication(sys.argv)
dlg = QDialog()
listWidget = QListWidget()
for i in range(100):
listWidget.addItem(QListWidgetItem("Item " + str(i)))
layout1 = QVBoxLayout()
layout1.addWidget(QLabel("Label 1"))
groupBox1 = QGroupBox("Group 1")
groupBox1.setLayout(layout1)
layout2 = QVBoxLayout()
layout2.addWidget(listWidget)
groupBox2 = QGroupBox("Group 2")
groupBox2.setLayout(layout2)
nestedWidgetLayout = QVBoxLayout()
nestedWidgetLayout.addWidget(groupBox1)
nestedWidgetLayout.addWidget(groupBox2)
nestedWidget = QWidget()
nestedWidget.setLayout(nestedWidgetLayout)
scrollArea = QScrollArea()
scrollArea.setWidget(nestedWidget)
mainLayout = QVBoxLayout()
mainLayout.addWidget(scrollArea)
dlg.setLayout(mainLayout)
dlg.show()
app.exec()
The #a_manthey_67 solution gives us a starting point but has several limitations:
It is calculated for a specific number of items so if items are added/deleted it will fail.
Manually set the height of each item instead of obtaining the height set by the style.
Considering the above, I have implemented a similar logic using sizeHintForRow(), in addition to enabling the widgetResizable property of the QScrollArea and disabling the verticalScrollBar.
import sys
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QGroupBox,
QLabel,
QListWidget,
QListWidgetItem,
QScrollArea,
QVBoxLayout,
QWidget,
)
class ListWidget(QListWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.model().rowsInserted.connect(self._recalcultate_height)
self.model().rowsRemoved.connect(self._recalcultate_height)
#pyqtSlot()
def _recalcultate_height(self):
h = sum([self.sizeHintForRow(i) for i in range(self.count())])
self.setFixedHeight(h)
if __name__ == "__main__":
app = QApplication(sys.argv)
dlg = QDialog()
listWidget = ListWidget()
for i in range(100):
listWidget.addItem(QListWidgetItem("Item " + str(i)))
layout1 = QVBoxLayout()
layout1.addWidget(QLabel("Label 1"))
groupBox1 = QGroupBox("Group 1")
groupBox1.setLayout(layout1)
layout2 = QVBoxLayout()
layout2.addWidget(listWidget)
groupBox2 = QGroupBox("Group 2")
groupBox2.setLayout(layout2)
nestedWidget = QWidget()
nestedWidgetLayout = QVBoxLayout(nestedWidget)
nestedWidgetLayout.addWidget(groupBox1)
nestedWidgetLayout.addWidget(groupBox2)
scrollArea = QScrollArea(widgetResizable=True)
scrollArea.setWidget(nestedWidget)
mainLayout = QVBoxLayout(dlg)
mainLayout.addWidget(scrollArea)
dlg.show()
sys.exit(app.exec_())
if the height of listwidget is bigger than the height of all all items all items are shown in listWidget but no scrollbar (of listWidget). in this snippet height of items is set by item.sizeHint() and the needed height of listwidget calculated 10 px bigger than needed for all items. sizeHint() needs QSize as parameter.
listWidget = QListWidget()
lineHeight = 20
items = 100
for i in range(items):
item = QListWidgetItem("Item " + str(i)) # get every item to set sizeHint()
item.setSizeHint(QSize(-1, lineHeight)) # -1 = width undefined
listWidget.addItem(item)
listWidget.setFixedHeight(items*lineHeight + 10) # set fixed height of listwidget
I'm trying to get the player's names and the color that they choose for a next step in the project. Getting the names is easy enough but the colors is a bit of a pain.
I don't know how to get the selected color and apply it the button using the QColorDialog. The ultimate goal is to get a structure with player name linked to the color they chose.
Here is what i have:
from PyQt5.QtWidgets import (
QLineEdit,
QWidget,
QApplication,
QLabel,
QMainWindow,
QGridLayout,
QColorDialog,
QPushButton,
QVBoxLayout,
QHBoxLayout,
)
import sys
class NamesPlayers(QMainWindow):
""" name screen, ask the names of the players """
def __init__(self, nb_players):
super().__init__()
self.layout_widget = QWidget()
self.player_names = []
self.player_colors = []
main_layout = QVBoxLayout()
names_layout = QGridLayout()
button_layout = QHBoxLayout()
button_list = []
for i in range(nb_players):
label = QLabel("Name :")
player_name = QLineEdit()
color_button = QPushButton("Color")
color_button.setStyleSheet("background-color: white")
names_layout.addWidget(label, i, 0)
names_layout.addWidget(player_name, i, 1)
names_layout.addWidget(color_button, i, 2)
button_list.append(color_button)
self.player_names.append(player_name)
self.player_colors.append(color_button.styleSheet())
self.confirm_button = QPushButton("Confirm")
button_layout.addWidget(self.confirm_button)
main_layout.addLayout(names_layout)
main_layout.addLayout(button_layout)
for button in button_list:
button.clicked.connect(self.open_colordialog)
self.layout_widget.setLayout(main_layout)
self.setCentralWidget(self.layout_widget)
def open_colordialog(self):
color_dialog = QColorDialog()
color_dialog.exec_()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = NamesPlayers(4)
window.show()
app.exec_()
My main issue i guess is the fact that the number of buttons for the color can vary and when I click on those buttons, the address for the QColorDialog is always the same which is not what I want.
Any help is appreciated
One possible solution is to use the sender() method to get the button pressed:
import sys
from PyQt5 import QtCore, QtWidgets
class NamesPlayers(QtWidgets.QMainWindow):
""" name screen, ask the names of the players """
def __init__(self, nb_players, parent=None):
super().__init__(parent)
names_layout = QtWidgets.QGridLayout()
for i in range(nb_players):
label = QtWidgets.QLabel("Name :")
player_name = QtWidgets.QLineEdit()
color_button = QtWidgets.QPushButton("Color")
color_button.setStyleSheet("background-color: white")
color_button.clicked.connect(self.open_colordialog)
names_layout.addWidget(label, i, 0)
names_layout.addWidget(player_name, i, 1)
names_layout.addWidget(color_button, i, 2)
self.confirm_button = QtWidgets.QPushButton("Confirm")
central_widget = QtWidgets.QWidget()
main_layout = QtWidgets.QVBoxLayout(central_widget)
button_layout = QtWidgets.QHBoxLayout()
button_layout.addWidget(self.confirm_button)
main_layout.addLayout(names_layout)
main_layout.addLayout(button_layout)
self.setCentralWidget(central_widget)
#QtCore.pyqtSlot()
def open_colordialog(self):
button = self.sender()
color_dialog = QtWidgets.QColorDialog()
if color_dialog.exec_() == QtWidgets.QColorDialog.Accepted:
button.setStyleSheet(
"background-color: {}".format(color_dialog.selectedColor().name())
)
button.clearFocus()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = NamesPlayers(4)
window.show()
sys.exit(app.exec_())
Another possible solution is to send the button pressed (with the methods indicated in this answer):
from functools import partial
# ...
for i in range(nb_players):
# ...
color_button = QtWidgets.QPushButton("Color")
color_button.setStyleSheet("background-color: white")
color_button.clicked.connect(partial(self.open_colordialog, color_button))
# or
# color_button.clicked.connect(lambda *args, btn=color_button: self.open_colordialog(btn))
def open_colordialog(self, button):
color_dialog = QtWidgets.QColorDialog()
if color_dialog.exec_() == QtWidgets.QColorDialog.Accepted:
button.setStyleSheet(
"background-color: {}".format(color_dialog.selectedColor().name())
)
button.clearFocus()
so I am trying to use PyQt5 to put a scroll area inside of a tab. Just playing around with a system that reads the serial port.
The issue I am having is that although I set a QVBoxLayout, the size does not seem to adjust to what I want it to be. It seems to be taking its minimum size and not adjusting.
I tried looking at the documentation on QSizePolicy on the website provided, but unfortunately it is all labeled as TODO.
https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtwidgets/qsizepolicy.html
I was wondering if anyone had some experience with this?
import sys
from PyQt5.QtWidgets import QMainWindow, QSizePolicy, QLabel, QGridLayout, QToolTip, QPlainTextEdit, QScrollArea, QApplication, QPushButton, QWidget, QAction, QTabWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtGui import *
from PyQt5.QtCore import pyqtSlot, QDateTime, Qt, pyqtSignal, QObject, QSize
import datetime
import serial
import serial.tools.list_ports
import threading
class FDSerial(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.connected = False
self.fd_line = ""
newAct = QAction(QIcon('icn/001-file.png'), 'New', self)
newAct.triggered.connect(self.init_sc)
self.toolbar = self.addToolBar('New')
self.toolbar.addAction(newAct)
openAct = QAction(QIcon('icn/002-folder.png'), 'Open', self)
self.toolbar.addAction(openAct)
connectAct = QAction(QIcon('icn/003-pendrive.png'), 'Connect', self)
connectAct.triggered.connect(self.find_port)
self.toolbar.addAction(connectAct)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
editMenu = menubar.addMenu('&Settings')
toolsMenu = menubar.addMenu('&Tools')
sessionMenu = menubar.addMenu('&Session')
helpMenu = menubar.addMenu('&Help')
self.statusBar().showMessage('Ready')
self.table_widget = LayoutWidgets(self)
self.setCentralWidget(self.table_widget)
self.setGeometry(400, 400, 800, 600)
self.setWindowTitle('FD Serial Demo')
self.show()
self.c = Communicate()
self.c.serialStuff.connect(lambda: self.table_widget.add_row(self.fd_line))
def init_sc(self):
self.ser = serial.Serial()
self.ser.baudrate = 115200
self.is_connected = False
self.tests_run = 0
self.port_found = False
def find_port(self):
if self.is_connected is False:
self.is_connected = True
else:
self.is_connected = False
for port in serial.tools.list_ports.comports():
if port.vid == 5824 and port.pid == 1155:
self.ser.port = str(port.device)
self.port_found = True
print("Found")
if self.port_found is False:
print("Not found")
x = threading.Thread(target=self.talk_module)
x.start()
def talk_module(self):
self.ser.open()
while self.is_connected is True:
self.fd_line = self.ser.readline().decode()
print(self.fd_line)
self.c.serialStuff.emit()
self.ser.close()
class Communicate(QObject):
serialStuff = pyqtSignal()
class LayoutWidgets(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.thisthat = 0
self.mySizePolicy = QSizePolicy()
self.mySizePolicy.setHorizontalStretch(1)
self.mySizePolicy.setVerticalStretch(1)
# self.mySizePolicy.setHeightForWidth(False)
# self.mySizePolicy.setHorizontalPolicy(QSizePolicy.Maximum)
# self.mySizePolicy.setVerticalPolicy(QSizePolicy.Maximum)
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.addTab(self.tab1, "Serial CANFD Interface")
self.tabs.addTab(self.tab2, "Data Visualizer")
self.tab1.layout = QVBoxLayout()
self.tab2.layout = QVBoxLayout()
self.scrollArea = QScrollArea(self.tab1)
self.scrollArea.setWidgetResizable(True)
# self.widget = QWidget()
# self.scrollArea.setWidget(self.widget)
self.layout_SArea = QVBoxLayout(self.scrollArea)
self.layout_SArea.setSpacing(0)
self.tab1.layout.addWidget(self.scrollArea)
self.scrollArea.setSizePolicy(self.mySizePolicy)
self.scrollArea.setStyleSheet("background-color:'#d3f3c8'")
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
self.qtextbig = QPlainTextEdit()
self.qtextbig.setSizePolicy(self.mySizePolicy)
self.qtextbig.setReadOnly(False)
self.layout_SArea.addWidget(self.qtextbig)
def add_row(self, row):
self.this = str(row)
self.this2 = str(datetime.datetime.now().time())
self.thisthat = self.thisthat + 1
self.qtextbig.appendPlainText(self.this)
self.qtextbig.appendPlainText(self.this2)
self.qtextbig.appendPlainText(str(self.thisthat))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = FDSerial()
sys.exit(app.exec_())
Here is how the GUI looks right now. The scroll are is way too small! It is in green.
I am looking for the scroll area to take the whole tab size, and then adjust as I adjust the window size. Would appreciate any pointers.
Thanks!
The problem has nothing to do with the QSizePolicy, they are not really necessary. The problem is that you are not using layouts. I think that using the following instruction:
self.tab1.layout = QVBoxLayout()
self.tab2.layout = QVBoxLayout()
add a layout to each tab, but it is only pointing out that there is a new property called layout that takes the value of the QVBoxLayout and that deletes the reference to the layout method of the tab, ie it only deletes the access to the tab1.layout() method, and doing it is a bad practice.
Considering the above I have used the following code:
# ...
class LayoutWidgets(QWidget):
def __init__(self, parent=None):
super(QWidget, self).__init__(parent)
layout = QVBoxLayout(self)
self.thisthat = 0
self.tabs = QTabWidget()
layout.addWidget(self.tabs)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.addTab(self.tab1, "Serial CANFD Interface")
self.tabs.addTab(self.tab2, "Data Visualizer")
lay = QVBoxLayout(self.tab1)
self.scrollArea = QScrollArea(widgetResizable=True)
self.scrollArea.setStyleSheet("background-color:'#d3f3c8'")
lay.addWidget(self.scrollArea)
layout_SArea = QVBoxLayout(self.scrollArea)
self.qtextbig = QPlainTextEdit(readOnly=False)
layout_SArea.addWidget(self.qtextbig)
def add_row(self, row):
self.this = str(row)
self.this2 = str(datetime.datetime.now().time())
self.thisthat = self.thisthat + 1
self.qtextbig.appendPlainText(self.this)
self.qtextbig.appendPlainText(self.this2)
self.qtextbig.appendPlainText(str(self.thisthat))
# ...
I'm not able to size correctly a table view element (self.table_View_1) inside a tab,
I tried different approaches like containers, layout and so on without reaching the objective.
The code refer to a model class that allows to show pandas data frame inside the table view.
here's the code:
import sys
import Mod_PX
from PandasModel import PandasModel
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QTabWidget, QVBoxLayout, QWidget, QMainWindow, QGroupBox
from PyQt5.QtCore import pyqtSlot
class ProgramWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setup_main_window()
self.set_window_layout()
def setup_main_window(self):
self.centralwidget = QWidget()
self.setCentralWidget(self.centralwidget)
self.resize( 800, 350 )
self.setWindowTitle( "ProjectX" )
def set_window_layout(self):
self.vbox_1 = QVBoxLayout(self.centralwidget)
self.hgroup_2 = QGroupBox()
self.hlayout_2 = QHBoxLayout()
self.hgroup_2.setLayout(self.hlayout_2)
self.btn_Analisi = QPushButton('Analisi', self)
self.btn_Help = QPushButton('Help')
self.btn_Wiz = QPushButton('Wizard')
self.btn_Analisi.clicked.connect(self.loadFile)
self.hlayout_2.addWidget(self.btn_Analisi)
self.hlayout_2.addWidget(self.btn_Help)
self.hlayout_2.addWidget(self.btn_Wiz)
self.vbox_1.addWidget(self.hgroup_2)
# Initialize tabs_1 screen
self.tabs_1 = QTabWidget()
self.tab1_1 = QWidget()
self.tab2_1 = QWidget()
self.tab3_1 = QWidget()
# Add tabs
self.tabs_1.addTab(self.tab1_1, "WWA")
self.tabs_1.addTab(self.tab2_1, "WTP")
self.tabs_1.addTab(self.tab3_1, "WTW")
# Add tabs to widget
self.vbox_1.addWidget(self.tabs_1)
# Initialize tabs_2 screen
self.tabs_2 = QTabWidget(self.tab1_1)
self.tab1_2 = QWidget()
self.tab2_2 = QWidget()
self.tabs_2.setTabPosition(QtWidgets.QTabWidget.West)
self.vbox_2 = QVBoxLayout(self.tab1_1)
# Add tabs
self.tabs_2.addTab(self.tab1_2, "Foglio 1")
self.tabs_2.addTab(self.tab2_2, "Foglio 2")
#Add tabs to widget
self.table_View_1 = QtWidgets.QTableView(self.tab1_2)
self.table_View_1.setObjectName("table_View_1")
font = QtGui.QFont()
font.setPointSize(10)
self.table_View_1.setFont(font)
self.table_View_1.setGeometry(0,0,self.tab1_2.width(),self.tab1_2.height())
self.vbox_2.addWidget(self.tabs_2)
self.show()
#pyqtSlot()
def loadFile(self):
df = Mod_PX.sheet_b()
model = PandasModel(df)
self.table_View_1.setModel(model)
def main():
app = QApplication(sys.argv)
programWindow = ProgramWindow()
programWindow.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Here the GUI with the table not correctly sized:
Thank you in advance for your support!
First you must correctly state the layouts and you should not use setGeometry since that is the task of the layouts. I have modified the structure of your code to have an order so at the end I point out the relationship between the layouts.
def set_window_layout(self):
#buttons
self.btn_Analisi = QtWidgets.QPushButton('Analisi')
self.btn_Help = QtWidgets.QPushButton('Help')
self.btn_Wiz = QtWidgets.QPushButton('Wizard')
# Initialize tabs_1 screen
self.tabs_1 = QtWidgets.QTabWidget()
self.tab1_1 = QtWidgets.QWidget()
self.tab2_1 = QtWidgets.QWidget()
self.tab3_1 = QtWidgets.QWidget()
# Add tabs
self.tabs_1.addTab(self.tab1_1, "WWA")
self.tabs_1.addTab(self.tab2_1, "WTP")
self.tabs_1.addTab(self.tab3_1, "WTW")
# Initialize tabs_2 screen
self.tabs_2 = QtWidgets.QTabWidget()
self.tab1_2 = QtWidgets.QWidget()
self.tab2_2 = QtWidgets.QWidget()
self.tabs_2.setTabPosition(QtWidgets.QTabWidget.West)
# Add tabs
self.tabs_2.addTab(self.tab1_2, "Foglio 1")
self.tabs_2.addTab(self.tab2_2, "Foglio 2")
self.table_View_1 = QtWidgets.QTableView()
font = QtGui.QFont()
font.setPointSize(10)
self.table_View_1.setFont(font)
# connections
self.btn_Analisi.clicked.connect(self.loadFile)
# layouts
vbox = QtWidgets.QVBoxLayout(self.centralwidget)
hgroup = QtWidgets.QGroupBox()
vbox.addWidget(hgroup)
hlay_group = QtWidgets.QHBoxLayout(hgroup)
hlay_group.addWidget(self.btn_Analisi)
hlay_group.addWidget(self.btn_Help)
hlay_group.addWidget(self.btn_Wiz)
vbox.addWidget(self.tabs_1)
lay = QtWidgets.QVBoxLayout(self.tab1_1)
lay.addWidget(self.tabs_2)
lay_tableview = QtWidgets.QVBoxLayout(self.tab1_2)
lay_tableview.addWidget(self.table_View_1)