A software tool has a table filled with two columns: parameter and data. "Data" column have comboBox widget. How to pass the listData
to the createEditor
function as a parameter, that I can assign listCombo
to the listData
?
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
import pandas as pd
class DataDelegate(QStyledItemDelegate):
def createEditor(self, parent, opt, index):
comboBox = QComboBox(parent)
listCombo = []
comboBox.addItems(listCombo)
comboBox.setCurrentIndex(1)
comboBox.currentTextChanged.connect(lambda: self.commitData.emit(comboBox))
return comboBox
class Window(QWidget):
singleton: 'Window' = None
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle("Software tool")
self.setGeometry(50, 50, 1800, 900)
self.mainLayout=QHBoxLayout()
self.setLayout(self.mainLayout)
self.UI()
self.table.itemChanged.connect(self._print)
def UI(self):
self.sublayouts = {}
self.buttons = {}
self._view()
self._fillTableWidget()
self.show()
def _view(self):
self.table = QTableWidget(0, 2)
self.table.setHorizontalHeaderLabels(['Parameter', 'Data'])
self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
self.sublayouts['table'] = QGridLayout()
self.sublayouts['table'].addWidget(self.table, 1, 0, 4, 4)
self.sublayouts['table'].setRowStretch(4, 1)
self.mainLayout.addLayout(self.sublayouts['table'])
self.table.setItemDelegateForColumn(1, DataDelegate(self.table))
def _fillTableWidget(self):
listCol = {
'Parameters': ['a', 'b', 'c', 'd', 'e'],
'Data': ['data1', 'data2', 'data3', 'data4', 'data5']}
self.df = pd.DataFrame(listCol)
listData = self.df['Data'].to_list()
print(listData)
for parameter in self.df['Parameters']:
rowPosition = self.table.rowCount()
self.table.insertRow(rowPosition)
self.table.setItem(rowPosition, 0, QTableWidgetItem(parameter))
dataItem = QTableWidgetItem()
self.table.setItem(rowPosition, 1, dataItem)
self.table.openPersistentEditor(self.table.item(rowPosition, 1))
def _tableCell(self, text):
item = QTableWidgetItem()
item.setText(text)
return item
def _print(self):
print('Item changed:')
def main():
App=QApplication(sys.argv)
window =Window()
sys.exit(App.exec_())
if __name__ == '__main__':
main()
CodePudding user response:
A possible solution is to set a default list as an instance attribute of the delegate, use that list within createEditor()
and overwrite it when the model is retrieved:
class DataDelegate(QStyledItemDelegate):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.items = []
def setItems(self, items):
self.items[:] = items
def createEditor(self, parent, opt, index):
comboBox = QComboBox(parent)
comboBox.addItems(self.items)
comboBox.setCurrentIndex(1)
comboBox.currentTextChanged.connect(
lambda: self.commitData.emit(comboBox))
return comboBox
class Window(QWidget):
# ...
def _view(self):
# ...
self.dataDelegate = DataDelegate(self.table)
self.table.setItemDelegateForColumn(1, self.dataDelegate)
def _fillTableWidget(self):
listCol = {
'Parameters': ['a', 'b', 'c', 'd', 'e'],
'Data': ['data1', 'data2', 'data3', 'data4', 'data5']}
self.df = pd.DataFrame(listCol)
listData = self.df['Data'].to_list()
self.dataDelegate.setItems(listData)
# ...
Note: the currentTextChanged
signal should be used when you actually need it (which is normally required for editable comboboxes, and might not be fired in certain situations); while that signal is usually emitted for uneditable combo boxes even when the same text exists in different items, that behavior might change in the future, and the currentIndexChanged
is usually preferred, especially for model editors, since the data should only be updated when the editor is actually submitted.