QTableWidget: signal to detect start of cell edit - python

I have a PyQt5 QTableWidget with two connected signals. One signal is meant to fire and print text to the screen when the user starts editing a cell in the table; the other is meant to fire and print text when the user finishes editing.
The latter works by connecting a function to the cellChanged signal; however, the cellActivated signal doesn't fire when the user starts editing a cell in the table.
To be clear: I want a catch-all signal for any time the cell editing starts (i.e. when the blinking cursor appears in a table cell indicating the user can now type in the cell). So connecting to the doubleClick signal will not do the trick. Although, I would settle for just having it fire when the user begins editing by pressing the enter key.
Here is my code:
from PyQt5 import QtCore, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(790, 472)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tbwMain = QtWidgets.QTabWidget(self.centralwidget)
self.tbwMain.setGeometry(QtCore.QRect(0, 0, 801, 451))
self.tbwMain.setObjectName("tbwMain")
self.tabBoxes = QtWidgets.QWidget()
self.tabBoxes.setObjectName("tabBoxes")
self.horizontalLayoutWidget = QtWidgets.QWidget(self.tabBoxes)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(0, 0, 791, 421))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem = QtWidgets.QSpacerItem(220, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.horizontalLayout.addItem(spacerItem)
self.tblBoxes = QtWidgets.QTableWidget(self.horizontalLayoutWidget)
self.tblBoxes.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.tblBoxes.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.tblBoxes.setRowCount(1)
self.tblBoxes.setObjectName("tblBoxes")
self.tblBoxes.setColumnCount(3)
item = QtWidgets.QTableWidgetItem()
self.tblBoxes.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tblBoxes.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tblBoxes.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.tblBoxes.setItem(0, 0, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.tblBoxes.setItem(0, 1, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.tblBoxes.setItem(0, 2, item)
self.tblBoxes.horizontalHeader().setStretchLastSection(True)
self.tblBoxes.verticalHeader().setVisible(False)
self.horizontalLayout.addWidget(self.tblBoxes)
spacerItem1 = QtWidgets.QSpacerItem(220, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.horizontalLayout.addItem(spacerItem1)
self.tbwMain.addTab(self.tabBoxes, "")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
self.tbwMain.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
# - - - - -
self.tblBoxes.cellActivated.connect(self.test1)
self.tblBoxes.cellChanged.connect(self.test2)
def test1(self):
print('Start cell edit!')
def test2(self):
print('End cell edit!')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
To reiterate, I'm looking for a solution for printing the text "Start Cell Edit" whenever a cell of the table begins to be edited.

There are several different ways to do this. One way is to reimplement the edit method of the table-widget, and emit a custom signal:
class TableWidget(QtWidgets.QTableWidget):
cellEditingStarted = QtCore.pyqtSignal(int, int)
def edit(self, index, trigger, event):
result = super(TableWidget, self).edit(index, trigger, event)
if result:
self.cellEditingStarted.emit(index.row(), index.column())
return result
However, if you're using Qt Designer, it might be preferrable to avoid sub-classing the table-widget, and use an item-delegate instead:
class ItemDelegate(QtWidgets.QStyledItemDelegate):
cellEditingStarted = QtCore.pyqtSignal(int, int)
def createEditor(self, parent, option, index):
result = super(ItemDelegate, self).createEditor(parent, option, index)
if result:
self.cellEditingStarted.emit(index.row(), index.column())
return result
class Ui_MainWindow(object):
...
def retranslateUi(self, MainWindow):
self.delegate = ItemDelegate(MainWindow)
self.delegate.cellEditingStarted.connect(self.test1)
self.tblBoxes.setItemDelegate(self.delegate)
self.tblBoxes.cellActivated.connect(self.test2)

Related

Add qcheckbox in every row of qtablewidget

I'm trying to add a checkbox in each row of a qtablewidget. When the table has more than one row, the checkbox is not inserted in the first row. Just in the last one. But the data coming from a db are inserted in every row. Can anyone please explain what I am doing wrong here.
checkbox = QtWidgets.QCheckBox()
income = helper.selectOne("""SELECT En_Kat.ID_En, En_Kat.ID_Kind, En_Kat.Entgelt_Kat, En_Kat.E_Start_Date
From En_Kat WHERE En_Kat.ID_Kind = ?""", (idc, ))
for rowi, i in enumerate(income):
self.ui.incomeTWG.insertRow(rowi)
self.ui.incomeTWG.setCellWidget(rowi,5,checkbox)
for coli, datai in enumerate(i):
celli = QtWidgets.QTableWidgetItem(str(datai))
self.ui.incomeTWG.setItem(rowi,coli,celli)
celli.setTextAlignment(Qt.AlignHCenter)
Now with reproducable code:
import sys
from ui.mainwindow import Ui_MainWindow
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
app = QtWidgets.QApplication(sys.argv)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
checkbox = QtWidgets.QCheckBox()
income = (('1', '2'),('3','4'))
for rowi, i in enumerate(income):
self.ui.tableWidget.insertRow(rowi)
self.ui.tableWidget.setCellWidget(rowi,2,checkbox)
for coli, datai in enumerate(i):
celli = QtWidgets.QTableWidgetItem(str(datai))
self.ui.tableWidget.setItem(rowi,coli,celli)
celli.setTextAlignment(Qt.AlignHCenter)
window = MainWindow()
window.show()
sys.exit(app.exec_())
and here is the ui:
efrom PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(230, 160, 351, 192))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(3)
self.tableWidget.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "a"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "b"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "c"))
In your code you have only created a single QCheckBox, and what happens is that if you set a widget to a certain item and that widget was already in another widget then it will be moved, another widget will not be created as you expect. The solution is to create widgets inside the loop:
income = (("1", "2"), ("3", "4"))
for rowi, i in enumerate(income):
checkbox = QtWidgets.QCheckBox()
self.ui.tableWidget.insertRow(rowi)
self.ui.tableWidget.setCellWidget(rowi, 2, checkbox)
for coli, datai in enumerate(i):
celli = QtWidgets.QTableWidgetItem(str(datai))
self.ui.tableWidget.setItem(rowi, coli, celli)
celli.setTextAlignment(Qt.AlignHCenter)

Select a text in PYQT to copy

I designed a windows desktop app with QT Designer and PYQT5. The problem is that, I can not select any item, text on main window, or on qtablewidget to paste it manually somewhere else. It will make things easier for users not for me. `
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(260, 160, 256, 192))
self.tableWidget.setRowCount(3)
self.tableWidget.setColumnCount(2)
self.tableWidget.setObjectName("tableWidget")
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(1, 0, item)
self.input_gunduz = QtWidgets.QLineEdit(self.centralwidget)
self.input_gunduz.setGeometry(QtCore.QRect(370, 70, 71, 20))
self.input_gunduz.setObjectName("input_gunduz")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(220, 70, 101, 21))
font = QtGui.QFont()
font.setPointSize(9)
font.setBold(True)
font.setWeight(75)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
__sortingEnabled = self.tableWidget.isSortingEnabled()
self.tableWidget.setSortingEnabled(False)
item = self.tableWidget.item(1, 0)
item.setText(_translate("MainWindow", "trial"))
self.tableWidget.setSortingEnabled(__sortingEnabled)
self.label_5.setText(_translate("MainWindow", "Gündüz (kWhr):"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
`
The code is as seen above. Please help me make the main window selectable
Copying of text does not work in the same way for every widget, because each widget type uses even radically different way to show or interact with text.
If you want to copy the text of a QLabel, you have to make it selectable (by using label.setTextInteractionFlags(Qt.TextSelectableByMouse)).
But if you want to copy the text from QTableWidget, things are very different, since a table allows interaction with their items that prevent a simple text selection.
Obviously, the most simple method would be to start editing the item (assuming it's editable) and select its text, but if you want other ways to do that, it depends on how you want to be able to copy the text.
A possibility is to use the ctrl+c keyboard shortcut. To do so, we need to install an event filter on the table widget:
from PyQt5 import QtCore, QtGui, QtWidgets
from mainwindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
# install an event filter on the table widget, so that we can filter all
# its event, including keyboard presses
self.tableWidget.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress and event == QtGui.QKeySequence.Copy:
# check if an index is currently selected and it has text
text = self.tableWidget.currentIndex().data()
if text:
# copy that text to the clipboard
QtWidgets.QApplication.clipboard().setText(text)
return super().eventFilter(source, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Note that in the example above I used the multiple inheritance method explained in the documentation about using Designer with ui files. You should never edit the files created by pyuic.
It's also possible to set a menu for the table widget and copy the text from there:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
# ...
# use the custom context menu policy for the table widget, so that we can
# connect the menu request to a slot
self.tableWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tableWidget.customContextMenuRequested.connect(self.showTableMenu)
def showTableMenu(self, pos):
# get the text of the index at the mouse cursor (if any)
text = self.tableWidget.indexAt(pos).data()
menu = QtWidgets.QMenu()
copyAction = menu.addAction('Copy')
if not text:
copyAction.setEnabled(False)
# show the menu
res = menu.exec_(QtGui.QCursor.pos())
if res == copyAction:
# if the menu has been triggered by the action, copy to the clipboard
QtWidgets.QApplication.clipboard().setText(text)

How to get selected items from QComboBox to be displayed in QTableWidget in PyQt5? (QComboBox has checkbox to pick items)

I have QTableWidget in which I have QComboBox in each row for particular column. My each QCombobox has multiple values with checkboxes. I want to display selected item/s from each combobox in the next respective column 'SelectedMonths' in the same row and remove them when unchecked (Vice-versa).
Until now I have Script ready which gives me what all items have been checked/unchecked but I dont know how to get the index of the row for which combobox is activated.
Snippet to get the workflow
Sample Code:
Code Generated by QtDesigner: Demo.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(464, 291)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(30, 30, 411, 221))
self.tableWidget.setRowCount(1)
self.tableWidget.setColumnCount(2)
self.tableWidget.setObjectName("tableWidget")
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(0, 0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(0, 1, item)
self.tableWidget.horizontalHeader().setVisible(False)
self.tableWidget.verticalHeader().setVisible(False)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
__sortingEnabled = self.tableWidget.isSortingEnabled()
self.tableWidget.setSortingEnabled(False)
item = self.tableWidget.item(0, 0)
item.setText(_translate("MainWindow", "Select Months"))
item = self.tableWidget.item(0, 1)
item.setText(_translate("MainWindow", "Selected Months"))
self.tableWidget.setSortingEnabled(__sortingEnabled)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Code which I have written: DemoCode.py
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QTableWidgetItem
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt
from datetime import date
from dateutil.relativedelta import relativedelta
from Demo import Ui_MainWindow
def CheckableCombobox(combo, options):
model = QStandardItemModel(len(options), 1)
firstItem = QtGui.QStandardItem("SelectMonths")
firstItem.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
firstItem.setSelectable(False)
model.setItem(0, 0, firstItem)
for i, area in enumerate(options):
item = QStandardItem(area)
item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
item.setData(Qt.Unchecked, Qt.CheckStateRole)
model.setItem(i+1, 0, item)
combo.setModel(model)
class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(DemoCode, self).__init__()
self.setupUi(self)
self.rowPosition = self.tableWidget.rowCount()
for row in range(0,3):
self.tableWidget.insertRow(self.rowPosition)
for column in range(0,2):
if column == 0:
self.ComboBox = QtWidgets.QComboBox()
dtStart = date.today()
self.Monthlist = []
for n in range(1, 5):
self.Monthlist.append((dtStart + relativedelta(months=-n)).strftime('1-%b-%Y'))
CheckableCombobox(self.ComboBox, self.Monthlist)
self.ComboBox.model().itemChanged.connect(self.on_itemChanged)
self.tableWidget.setCellWidget(self.rowPosition, column, self.ComboBox)
elif column == 1:
item = QTableWidgetItem('')
self.tableWidget.setItem(self.rowPosition, column, item)
self.rowPosition += 1
self.tableWidget.setColumnWidth(1,150)
def on_itemChanged(self, item):
current_state = item.data(Qt.CheckStateRole)
print(current_state, item.text())
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = DemoCode()
window.show()
sys.exit(app.exec_())
You should find a way to keep track of the row for each combo model, so that you can set the item text accordingly.
Note that I changed your code logic a bit, as there were some conceptual mistakes:
don't set instance attributes if they are not required: all those self.rowPosition, self.monthList, etc, change everytime the for loop cycles, and you don't need them after that;
avoid using uppercase names for variables and functions
the month list is always the same, build it before the for cycle instead of computing it each time
instead of setting the model to the combo in the function, make it return the model
Edit: added copy function after comment request
def createModel(options):
model = QStandardItemModel(len(options), 1)
firstItem = QtGui.QStandardItem("SelectMonths")
firstItem.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
firstItem.setSelectable(False)
model.setItem(0, 0, firstItem)
for i, area in enumerate(options):
item = QStandardItem(area)
item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
item.setData(Qt.Unchecked, Qt.CheckStateRole)
model.setItem(i+1, 0, item)
return model
class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(DemoCode, self).__init__()
self.setupUi(self)
monthList = [(date.today() + relativedelta(months=-n)).strftime('1-%b-%Y') for n in range(1, 5)]
self.models = {}
rows = self.tableWidget.rowCount()
for row in range(rows, rows + 3):
self.tableWidget.insertRow(row)
comboBox = QtWidgets.QComboBox()
model = createModel(monthList)
comboBox.setModel(model)
model.itemChanged.connect(lambda _, row=row: self.on_itemChanged(row))
self.models[row] = model
self.tableWidget.setCellWidget(row, 0, comboBox)
item = QTableWidgetItem()
self.tableWidget.setItem(row, 1, item)
self.tableWidget.setColumnWidth(1,150)
def on_itemChanged(self, tableRow):
model = self.models[tableRow]
items = []
for row in range(model.rowCount()):
comboItem = model.index(row, 0)
if comboItem.data(Qt.CheckStateRole):
items.append(comboItem.data())
self.tableWidget.item(tableRow, 1).setText(', '.join(items))
def copyFromRow(self, tableRow):
sourceModel = self.models[tableRow]
checkedRows = []
for row in range(sourceModel.rowCount()):
if sourceModel.index(row, 0).data(Qt.CheckStateRole):
checkedRows.append(row)
for model in self.models.values():
if model == sourceModel:
continue
for row in range(model.rowCount()):
model.setData(
model.index(row, 0),
Qt.Checked if row in checkedRows else Qt.Unchecked,
Qt.CheckStateRole)
I'd also suggest to remove the "Select Months" and "Selected Months" items, and use them as table headers.

PyQt5 How to identify and grab data from a QT combobox that has been created along with other combobox using a function

I wrote a script that automatically creates a QT "object" made up of a category label, a combobox_1 with possible attributes, a push button and a combobox_2 to list all values available for the attribute selected. the script creates as many of these "objects" as necessary.
For each "object" the push button created is meant to grab the selected attribute in combobox_1 and use this information to retrieve relevant values from the database and populate combobx_2
Now the problem I have is that I can't figure out how to reference the comboboxes once they have been created. For the buttons, I use the serve function which listen to any button for a click so that's fine, but how can I reference combobox that have been created with a function. Although they all have different setObjectName, there doesn't seem to be a way of referencing that attribute so when I click on any button they all return the value of the last object's combobox instead of the value of its related comboxbox to which they are attached.
here is the Frontend script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(709, 357)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.gridLayout_4 = QtWidgets.QGridLayout()
self.gridLayout_4.setObjectName("gridLayout_4")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout_4.addItem(spacerItem, 1, 1, 1, 1)
self.VLayout_0 = QtWidgets.QVBoxLayout()
self.VLayout_0.setObjectName("VLayout_0")
self.HLayout_0 = QtWidgets.QHBoxLayout()
self.HLayout_0.setObjectName("HLayout_0")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.HLayout_0.addItem(spacerItem1)
self.CB_L0 = QtWidgets.QComboBox(self.centralwidget)
self.CB_L0.setObjectName("CB_L0")
self.HLayout_0.addWidget(self.CB_L0)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
self.pushButton.setMaximumSize(QtCore.QSize(40, 16777215))
self.pushButton.setObjectName("pushButton")
self.HLayout_0.addWidget(self.pushButton)
spacerItem2 = QtWidgets.QSpacerItem(50, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.HLayout_0.addItem(spacerItem2)
self.VLayout_0.addLayout(self.HLayout_0)
spacerItem3 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
self.VLayout_0.addItem(spacerItem3)
self.gridLayout_4.addLayout(self.VLayout_0, 1, 0, 1, 1)
self.PB_create_cb = QtWidgets.QPushButton(self.centralwidget)
self.PB_create_cb.setObjectName("PB_create_cb")
self.gridLayout_4.addWidget(self.PB_create_cb, 0, 1, 1, 1)
self.gridLayout.addLayout(self.gridLayout_4, 0, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 709, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "search"))
self.PB_create_cb.setText(_translate("MainWindow", "Create dropdown"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
and here is the backend example (which creates two "objects"):
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QAction, QTableWidget, QTableWidgetItem, QVBoxLayout, QMessageBox, QDialog, QLineEdit, QPushButton, QMenu, QSizePolicy, QLabel,QTreeWidget,QTreeWidgetItem
from PyQt5.QtWidgets import (QApplication, QWidget, QToolTip, QPushButton, QMessageBox)
import sys
from test3 import *
class Run_script(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Run_script, self).__init__(parent)
self.setupUi(self)
print("Run script initizalised")
self.PB_create_cb.clicked.connect(self.click_select)
def create_V_0_object(self,List_attributes):
V_list = []
for i,x in enumerate(List_attributes):
for k,v in x.items():
if type(v) == dict:
for k1,v1 in v.items():
if type(v) == dict:
self.HLayout_1 = QtWidgets.QHBoxLayout()
self.HLayout_1.setObjectName("H_layout_1")
self.VLayout_0 = QtWidgets.QVBoxLayout()
self.VLayout_0.setObjectName("V_L2"+k+str(i))
self.Attr_label = QtWidgets.QLabel(self.centralwidget)
self.Attr_label.setObjectName(k)
self.Attr_label.setText(k)
self.VLayout_0.addWidget(self.Attr_label)
self.attr_list = []
for k1,v1 in v.items():
self.attr_list.append(k1)
print("K1 is "+str(k1))
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setObjectName("CB_"+k)
self.comboBox.addItems(self.attr_list)
self.comboBox.setToolTip("CB_"+k)
self.VLayout_0.addWidget(self.comboBox)
self.comboBox1 = QtWidgets.QComboBox(self.centralwidget)
self.comboBox1.setObjectName("CB_l2_"+k)
self.comboBox1.setToolTip("CB_l2_"+k)
self.VLayout_0.addWidget(self.comboBox1)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
self.pushButton.setMaximumSize(QtCore.QSize(40, 16777215))
PB_name = "PB_"+str(k)
self.pushButton.setObjectName(PB_name)
self.pushButton.setToolTip("Search " + str(PB_name))
self.pushButton.setText(PB_name)
self.pushButton.clicked.connect(self.buttonClicked)
self.HLayout_1.addLayout(self.VLayout_0)
self.HLayout_1.addWidget(self.pushButton)
else:
pass
V_list.append(self.HLayout_1)
return V_list
def buttonClicked(self):
sender = self.sender()
cat_l_0 = sender.text()
for i in range(self.VLayout_0.count()):
name = self.VLayout_0.itemAt(i).widget().objectName()
print("this is:",name)
def click_select(self):
self.selection = [{"Category1":{"Attr1": "test1","Attr2":"test2"}},{"Category2":{"Attr1":"test3","Attr2":"test4"}}]
self.v = self.create_V_0_object(self.selection)
self.create_horizontal_display(self.v)
def deleteItemsOfLayout(self,layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.setParent(None)
else:
self.deleteItemsOfLayout(item.layout())
def create_horizontal_display(self,vertical_layout_list):
self.deleteItemsOfLayout(self.HLayout_0)
for i,x in enumerate(vertical_layout_list):
self.HLayout_0.addLayout(x)
if __name__ == '__main__':
app = QApplication(sys.argv)
prog = Run_script()
prog.show()
sys.exit(app.exec_())
to create the objects just press the "create dropdown" button
You have many bad practices:
The variables that are created in a loop are generally not going to be a member of the class because they are temporary variables, so do not use them as they will be overwritten, therefore when accessing self.VLayout_0 you will always get the last element.
Another bad habit is that everything you want to do in one place, as you say the "object" s are similar except for the data so you should create a class that builds it, as they say: divide and conquer.
You have other errors but they are minor, correcting the above you have the following:
from PyQt5 import QtCore, QtGui, QtWidgets
from test3 import Ui_MainWindow
class Widget(QtWidgets.QWidget):
clicked = QtCore.pyqtSignal()
def __init__(self, text, values, parent=None):
super(Widget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout(self)
vlay = QtWidgets.QVBoxLayout()
self.label = QtWidgets.QLabel(text)
self.combobox_1 = QtWidgets.QComboBox()
self.combobox_1.addItems(values.keys())
self.combobox_2 = QtWidgets.QComboBox()
vlay.addWidget(self.label)
vlay.addWidget(self.combobox_1)
vlay.addWidget(self.combobox_2)
hlay.addLayout(vlay)
self.button = QtWidgets.QPushButton(text)
self.button.clicked.connect(self.clicked)
hlay.addWidget(self.button)
self.setFixedSize(self.sizeHint())
class Run_script(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Run_script, self).__init__(parent)
self.setupUi(self)
print("Run script initizalised")
self.PB_create_cb.clicked.connect(self.click_select)
def create_V_0_object(self, attributes):
v_list = []
for x in attributes:
for key, value in x.items():
w = Widget(key, value)
w.clicked.connect(self.buttonClicked)
v_list.append(w)
return v_list
def buttonClicked(self):
w = self.sender()
print(w.combobox_1.currentText())
print(w.combobox_2.currentText())
print(w.label.text())
print(w.button.text())
def click_select(self):
selection = [{"Category1":{"Attr1": "test1","Attr2":"test2"}},{"Category2":{"Attr1": "test3", "Attr2": "test4"}}]
v = self.create_V_0_object(selection)
self.create_horizontal_display(v)
def deleteItemsOfLayout(self,layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.setParent(None)
else:
self.deleteItemsOfLayout(item.layout())
def create_horizontal_display(self, vertical_layout_list):
self.deleteItemsOfLayout(self.HLayout_0)
for i, x in enumerate(vertical_layout_list):
self.HLayout_0.addWidget(x)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
prog = Run_script()
prog.show()
sys.exit(app.exec_())

How to get selected item in table using pyqt?

I display data in a table from mysql database,
after that I want to when the rows in the table is clicked it will print the value in the line,that in print id existing data in the database. How do I make it to be like that?
Here's the source code:
from PyQt4 import QtCore, QtGui
import sys
import MySQLdb
from form.DBConnection import Connection
import MySQLdb as mdb
db = Connection()
myCursor = db.name().cursor()
"................................................
....................................."
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(655, 356)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.tbl_anggota = QtGui.QTableWidget(self.centralwidget)
self.tbl_anggota.setGeometry(QtCore.QRect(15, 40, 511, 192))
self.tbl_anggota.setObjectName(_fromUtf8("tbl_anggota"))
self.tbl_anggota.setColumnCount(3)
self.tbl_anggota.setRowCount(0)
item = QtGui.QTableWidgetItem()
self.tbl_anggota.setHorizontalHeaderItem(0, item)
item = QtGui.QTableWidgetItem()
self.tbl_anggota.setHorizontalHeaderItem(1, item)
item = QtGui.QTableWidgetItem()
self.tbl_anggota.setHorizontalHeaderItem(2, item)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 655, 21))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
self.table(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
item = self.tbl_anggota.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "NIM", None))
item = self.tbl_anggota.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "NAMA", None))
item = self.tbl_anggota.horizontalHeaderItem(2)
def table(self, MainWindow):
myCursor.execute("SELECT * FROM anggota")
jum_baris= myCursor.fetchall()
self.tbl_anggota.setRowCount(len(jum_baris))
self.tbl_anggota.setColumnCount(3)
for i in range (len(jum_baris)):
for j in range (3):
item = Qt.QTableWidgetItem('%s' % (jum_baris[i][j + 1]))
self.tbl_anggota.setItem(i, j, item)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
This line of code will select the current row
r = self.tbl_anggota.currentRow()
If you know your columns (ie. it's not dynamic) you can then pull the value of each of your cells by doing this:
field1 = self.tbl_anggota.item(r,0).text()
field2 = self.tbl_anggota.item(r,1).text()
In this case, the 0 and the 1 in the item call are your columns, in a 0 indexed array. Remember that hidden columns still count.
To do this automatically when a row is clicked, you'll want to use the signal itemClicked

Categories