The code below creates a single QTableView
. Double-clicking its item will set it with a delegated QComboBox
.
Problem:
When the ComboBox
is clicked its pull-down menu shows up momentary and then it collapses back to its unrolled state.
If the comboBox
would be set to be editable using combox.setEditable(True)
,
the pull-down menu would stay open as desired. But then the combobox
's items become editable. And it is not what needed. Since the combobox
's items should only be selectable.
How to fix the self-collapsing combobox
's behavior?
P.s. I have noticed then when ComboBox
is set to be editable and its pull-down menu is unrolled the model's data()
is constantly being called... is self-collapsing behavior could probably triggered by model?
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_())
Your original code is working in PyQt5, the combobox
stays open. But the user has to click to open the editor and then to click to open the combobox
. To avoid this i replaced QComboBox
by QlistWidget
in your code. Additionally i set 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_())