python qt pyqt qtableview qcombobox

python - Cómo usar QComboBox como delegado con QTableView



pyqt (2)

El código siguiente crea un solo QTableView. Al hacer doble clic en su elemento se establecerá con un QComboBox delegado.

Problema : cuando se hace clic en el ComboBox, su menú desplegable aparece momentáneamente y luego vuelve a su estado desenrollado.

Si comboBox se configurara para ser editable usando:

combo.setEditable(True)

el menú desplegable permanecería abierto según lo deseado. Pero luego los elementos del combobox se vuelven editables. Y no es lo que necesitaba Dado que los elementos del combobox solo se pueden seleccionar.

¿Cómo corregir el comportamiento de la caja combinada autocolapsable?

Ps He notado que cuando ComboBox se configura para ser editable y se desenrolla su menú desplegable, los data() del modelo data() se llaman constantemente ... ¿Es probable que el comportamiento de auto colapso pueda ser desencadenado por el modelo?

import sys from PyQt4.QtCore import * from PyQt4.QtGui import * class ComboDelegate(QItemDelegate): comboItems=[''Combo_Zero'', ''Combo_One'',''Combo_Two''] def createEditor(self, parent, option, proxyModelIndex): combo = QComboBox(parent) combo.addItems(self.comboItems) # combo.setEditable(True) self.connect(combo, SIGNAL("currentIndexChanged(int)"), self, SLOT("currentIndexChanged()")) return combo def setModelData(self, combo, model, index): comboIndex=combo.currentIndex() text=self.comboItems[comboIndex] model.setData(index, text) print ''/t/t/t ...setModelData() 1'', text @pyqtSlot() def currentIndexChanged(self): self.commitData.emit(self.sender()) class MyModel(QAbstractTableModel): def __init__(self, parent=None, *args): QAbstractTableModel.__init__(self, parent, *args) self.items=[''Data_Item01'',''Data_Item02'',''Data_Item03''] def rowCount(self, parent=QModelIndex()): return len(self.items) def columnCount(self, parent=QModelIndex()): return 1 def data(self, index, role): if not index.isValid(): return QVariant() row=index.row() item=self.items[row] if row>len(self.items): return QVariant() if role == Qt.DisplayRole: print '' << >> MyModel.data() returning ...'', item return QVariant(item) def flags(self, index): return Qt.ItemIsEditable | Qt.ItemIsEnabled def setData(self, index, text): self.items[index.row()]=text if __name__ == ''__main__'': app = QApplication(sys.argv) model = MyModel() tableView = QTableView() tableView.setModel(model) delegate = ComboDelegate() tableView.setItemDelegate(delegate) tableView.resizeRowsToContents() tableView.show() sys.exit(app.exec_())


Aquí está el intento de sustituir un QComboBox con QToolButton vinculado a QMenu y QAction s.

La apariencia es casi lo mismo que QComboBox con una característica adicional de tener la capacidad de configurar múltiples QActions comprobadas (actualmente no es posible tener múltiples elementos de ComboBoxes marcados).

import sys from PyQt4.QtCore import * from PyQt4.QtGui import * class ComboDelegate(QItemDelegate): comboItems=[''Combo_Zero'', ''Combo_One'',''Combo_Two''] def __init__(self, parent): QItemDelegate.__init__(self, parent=None) self.actionEmitted=None def createEditor(self, parent, option, index): if not index.isValid(): return model=index.model() itemName=model.data(index, Qt.DisplayRole) toolButton=QToolButton(parent) toolButton.setText( itemName.toString() ) toolButton.setPopupMode(QToolButton.InstantPopup) menu=QMenu(parent) action1=QAction(''Action 01'', menu, checkable=True) action2=QAction(''Action 02'', menu, checkable=True) action3=QAction(''Action 03'', menu, checkable=True) action1.setObjectName(''Action 01'') action2.setObjectName(''Action 02'') action3.setObjectName(''Action 03'') action1.setChecked(True) action3.setChecked(True) self.connect(action1, SIGNAL("triggered(bool)"), self, SLOT("actionTriggered()")) self.connect(action2, SIGNAL("triggered(bool)"), self, SLOT("actionTriggered()")) self.connect(action3, SIGNAL("triggered(bool)"), self, SLOT("actionTriggered()")) menu.addAction(action1) menu.addAction(action2) menu.addAction(action3) toolButton.setMenu(menu) return toolButton def setModelData(self, toolButton, model, index): print ''/t/t/t ...setModelData() 1'', toolButton, model, index if not self.actionEmitted: return menu=toolButton.menu() for action in menu.actions(): actionName=action.objectName() actionStatus=action.isChecked() if actionStatus: model.setData(index, actionName) print ''####'', actionName, actionStatus @pyqtSlot() def actionTriggered(self): self.actionEmitted=self.sender() self.commitData.emit( self.actionEmitted ) print ''actionTriggered.....'', self.actionEmitted class MyModel(QAbstractTableModel): def __init__(self, parent=None, *args): QAbstractTableModel.__init__(self, parent, *args) self.items=[''Data_Item01'',''Data_Item02'',''Data_Item03''] def rowCount(self, parent=QModelIndex()): return len(self.items) def columnCount(self, parent=QModelIndex()): return 1 def data(self, index, role): if not index.isValid(): return QVariant() row=index.row() item=self.items[row] if row>len(self.items): return QVariant() if role == Qt.DisplayRole: print '' << >> MyModel.data() returning ...'', item return QVariant(item) def flags(self, index): return Qt.ItemIsEditable | Qt.ItemIsEnabled def setData(self, index, itemName): self.items[index.row()]=itemName if __name__ == ''__main__'': app = QApplication(sys.argv) combo=QComboBox() combo.addItems([''Combo_Zero'', ''Combo_One'',''Combo_Two'']) model = MyModel() tableView = QTableView() tableView.setModel(model) delegate = ComboDelegate(tableView) tableView.setItemDelegate(delegate) tableView.resizeRowsToContents() tableView.show() sys.exit(app.exec_())


Su código original está funcionando en PyQt5, el cuadro combinado permanece abierto. Pero el usuario tiene que hacer clic para abrir el editor y luego hacer clic para abrir el cuadro combinado. Para evitar esto, reemplacé QComboBox por QlistWidget en tu código. Además, establecí editorGeometry:

import sys # from PyQt4.QtCore import * # from PyQt4.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * class ComboDelegate(QItemDelegate): editorItems=[''Combo_Zero'', ''Combo_One'',''Combo_Two''] height = 25 width = 200 def createEditor(self, parent, option, index): editor = QListWidget(parent) # editor.addItems(self.editorItems) # editor.setEditable(True) editor.currentItemChanged.connect(self.currentItemChanged) return editor def setEditorData(self,editor,index): z = 0 for item in self.editorItems: ai = QListWidgetItem(item) editor.addItem(ai) if item == index.data(): editor.setCurrentItem(editor.item(z)) z += 1 editor.setGeometry(0,index.row()*self.height,self.width,self.height*len(self.editorItems)) def setModelData(self, editor, model, index): editorIndex=editor.currentIndex() text=editor.currentItem().text() model.setData(index, text) # print ''/t/t/t ...setModelData() 1'', text @pyqtSlot() def currentItemChanged(self): self.commitData.emit(self.sender()) class MyModel(QAbstractTableModel): def __init__(self, parent=None, *args): QAbstractTableModel.__init__(self, parent, *args) self.items=[''Data_Item01'',''Data_Item02'',''Data_Item03''] def rowCount(self, parent=QModelIndex()): return len(self.items) def columnCount(self, parent=QModelIndex()): return 1 def data(self, index, role): if not index.isValid(): return QVariant() row=index.row() item=self.items[row] if row>len(self.items): return QVariant() if role == Qt.DisplayRole: # print '' << >> MyModel.data() returning ...'', item return QVariant(item) def flags(self, index): return Qt.ItemIsEditable | Qt.ItemIsEnabled def setData(self, index, text): self.items[index.row()]=text if __name__ == ''__main__'': app = QApplication(sys.argv) model = MyModel() tableView = QTableView() tableView.setModel(model) delegate = ComboDelegate() tableView.setItemDelegate(delegate) for i in range(0,tableView.model().rowCount()): tableView.setRowHeight(i,tableView.itemDelegate().height) for i in range(0,tableView.model().columnCount()): tableView.setColumnWidth(i,tableView.itemDelegate().width) tableView.show() sys.exit(app.exec_())