Unsolved QComboBox editor showPopup incorrect placment of listview
-
I have a custom delegate that has a QComboBox as an editor for a tableview. I would like the ComboBox to auto expand and show the list view when the user double clicks the cell. Currently its double click to initiate the editor and then another click to expand to show the pop up.
I found the ComboBox has a .showPopup(), but when I use this, it provides the behavior of only using two clicks to expand the editor BUT always places the popup under the first cell upon the first edit event of the cell.
Is the creatEditor() the wrong place to call the showPopup? Or should I use some signal or editHint instead? Feels like Qt doesn't have all the information it needs and places the popup under the first cell
On windows 10, Qt 5.13
from PySide2 import QtGui, QtCore, QtWidgets import sys class CustomTableDelegate(QtWidgets.QStyledItemDelegate): def __init__(self, parent=None): super(CustomTableDelegate, self).__init__(parent) def createEditor(self, parent, option, index): """Create the ComboBox editor view.""" if index.column() == 0: editor = QtWidgets.QComboBox(parent) editor.addItems(['v001', 'v002', 'v003']) # !! this causes the pop up in incorrect place editor.showPopup() editor.activated.connect(self.commitAndCloseEditor) return editor def setEditorData(self, editor, index): """Set the ComboBox's current index.""" value = index.data(QtCore.Qt.DisplayRole) i = editor.findText(value) if i == -1: i = 0 editor.setCurrentIndex(i) def commitAndCloseEditor(self): editor = self.sender() self.commitData.emit(editor) self.closeEditor.emit(editor, QtWidgets.QStyledItemDelegate.NoHint) def setModelData(self, editor, model, index): """Set the table's model's data when finished editing.""" value = editor.currentText() model.setData(index, value) if __name__ == '__main__': app = QtWidgets.QApplication([]) data = [["v001", "stuff", "fixing source", '2020-01-14', ''], ["v002", "more stuff", "currently broken", '2020-06-30', ''], ["v003", "too much stuff", "scaling issues", '2020-02-08', ''], ["v088", "still missing stuff", "not coment", '2020-11-13', ''], ] table_view = QtWidgets.QTableView() table_view.setItemDelegate(CustomTableDelegate(table_view)) model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['version', 'file', 'comment', 'date', '']) table_view.setModel(model) for r in range(len(data)): for c in range(5): model.setItem(r, c, QtGui.QStandardItem(data[r][c])) table_view.show() sys.exit(app.exec_())
-
Okay first I adjusted your program to be a bit more python-pyqt-ish -- and after doing that I found that the "ComboBox" gets placed correctly it is just the
.showPopup()
that was miss placing it -- this says to me that you should not be using.showPopup()
event but the event that gets triggered when you click that down arrow for the ComboBox -- here is the adjusted codefrom PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtWidgets import * class CustomTableDelegate(QStyledItemDelegate): def __init__(self): QStyledItemDelegate.__init__(self) pass def createEditor(self, parent, option, index): """Create the ComboBox editor view.""" if index.column() == 0: editor = QComboBox(parent) editor.addItems(['v001', 'v002', 'v003']) # !! this causes the pop up in incorrect place # editor.showPopup() editor.activated.connect(self.commitAndCloseEditor) return editor def setEditorData(self, editor, index): """Set the ComboBox's current index.""" value = index.data(Qt.DisplayRole) i = editor.findText(value) if i == -1: i = 0 editor.setCurrentIndex(i) @Slot() def commitAndCloseEditor(self): editor = self.sender() self.commitData.emit(editor) self.closeEditor.emit(editor, QStyledItemDelegate.NoHint) def setModelData(self, editor, model, index): """Set the table's model's data when finished editing.""" value = editor.currentText() model.setData(index, value) class CstmTableView(QTableView): def __init__(self): QTableView.__init__(self) self.resize(450, 200) data = [["v001", "stuff", "fixing source", '2020-01-14'], ["v002", "more stuff", "currently broken", '2020-06-30'], ["v003", "too much stuff", "scaling issues", '2020-02-08'], ["v088", "still missing stuff", "not comment", '2020-11-13'], ] self.CstmTblDel = CustomTableDelegate() self.setItemDelegate(self.CstmTblDel) model = QStandardItemModel() model.setHorizontalHeaderLabels(['Version', 'File', 'Comment', 'Date']) self.setModel(model) for row in range(len(data)): for col in range(4): model.setItem(row, col, QStandardItem(data[row][col])) if __name__ == '__main__': MainEvntHndlr = QApplication([]) MainApp = CstmTableView() MainApp.show() MainEvntHndlr.exec() # If anyone wants more extensive free help I run an online lab-like classroom-like # message server feel free and drop by you will not be able to post until I clear # you as a student as this prevents spammers so if interested here is the invite # https://discord.gg/3D8huKC
-
@Denni-0
Sorry does your code have the event to trigger the dropdow instead of the .showPopup?Also you decorated the commitAndCloseEditor(), what is the purpose of that? and did you mean to use "@Slot" instead? I thought @pyqtslot is a pyqt5 decorator.
https://www.learnpyqt.com/blog/pyqt5-vs-pyside2/Cheers
-
oh sorry yeah I do pyqt5 forgot about the pyqtSlot being only Slot for PySide2 fixed that in the above code
Next no I did not supply the code to auto-drop-down your combobox list as I figured since I fixed your problem and I pointed it out you would be able to implement that aspect if you wanted it
The decorator is something you should use in the case of all function/methods that are associated with a
.connection( )
as the.connect( )
is a Signal and while you can get by without using Slots doing so can create hidden issues within your code later on so it always best to be explicit -- it is not like that little one-liner is all that difficult to include so do yourself a favor and start including it always (aka do not develop lazy coder habits as those are only problematic) -
no worries,
So I was able to try an event filter and test if a HoverEnter event happened, Then trigger the show pop up. Seems to solve the placement issue, not sure if this is the proper way of handling this,but gets the job done so far.
from PySide2 import QtGui, QtCore, QtWidgets import sys class CustomTableDelegate(QtWidgets.QStyledItemDelegate): def __init__(self, parent=None): super(CustomTableDelegate, self).__init__(parent) def createEditor(self, parent, option, index): """Create the ComboBox editor view.""" if index.column() == 0: editor = QtWidgets.QComboBox(parent) editor.addItems(['v001', 'v002', 'v003']) editor.installEventFilter(self) editor.activated.connect(self.commitAndCloseEditor) return editor def setEditorData(self, editor, index): """Set the ComboBox's current index.""" value = index.data(QtCore.Qt.DisplayRole) i = editor.findText(value) if i == -1: i = 0 editor.setCurrentIndex(i) def commitAndCloseEditor(self): editor = self.sender() self.commitData.emit(editor) self.closeEditor.emit(editor, QtWidgets.QStyledItemDelegate.NoHint) def setModelData(self, editor, model, index): """Set the table's model's data when finished editing.""" value = editor.currentText() model.setData(index, value) def eventFilter(self, p_object, event): if event.type() == QtCore.QEvent.Type.HoverEnter: p_object.showPopup() return True else: return False if __name__ == '__main__': app = QtWidgets.QApplication([]) data = [["v001", "stuff", "fixing source", '2020-01-14', ''], ["v002", "more stuff", "currently broken", '2020-06-30', ''], ["v003", "too much stuff", "scaling issues", '2020-02-08', ''], ["v088", "still missing stuff", "not coment", '2020-11-13', ''], ] table_view = QtWidgets.QTableView() table_view.setItemDelegate(CustomTableDelegate(table_view)) model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['version', 'file', 'comment', 'date', '']) table_view.setModel(model) for r in range(len(data)): for c in range(5): model.setItem(r, c, QtGui.QStandardItem(data[r][c])) table_view.show() sys.exit(app.exec_())