Search code examples
pythonpyqtpyqt4

Popup QCompleter in QStyledItemDelegate immediately without text input


I have a QCompleter on a QTableWidget column. As soon as the user starts editing I would like the completer to pop up, not waiting for them to enter text first. I subclassed the setEditorData function of the QStyledItemDelegate to do this which seems to make the most sense to me, however when I call completer.complete() nothing happens until I finish editing (at which point the popup fires).

Here is my code for the delegate:

class CompleterItemDelegate(QtGui.QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        completer = QtGui.QCompleter(['test', 'test2'])
        completer.setCompletionMode(completer.UnfilteredPopupCompletion)

        edit = QtGui.QLineEdit(parent)
        edit.setCompleter(completer)
        return edit

    def setEditorData(self, editor, index):
        completer = editor.completer()
        completer.complete() # does not fire until after editing is done
        completer.popup().show() # no luck here either
        print("setting editor data") # this however does work as expected...
        super().setEditorData(editor, index)

Solution

  • You have to call complete() when the widget is displayed and for this you can use the showEvent() method:

    from PyQt4 import QtCore, QtGui
    
    
    class LineEdit(QtGui.QLineEdit):
        def showEvent(self, event):
            if self.completer() is not None:
                QtCore.QTimer.singleShot(0, self.completer().complete)
            super().showEvent(event)
    
    
    class CompleterItemDelegate(QtGui.QStyledItemDelegate):
        def createEditor(self, parent, option, index):
            completer = QtGui.QCompleter(["test", "test2"])
            completer.setCompletionMode(QtGui.QCompleter.UnfilteredPopupCompletion)
            edit = LineEdit(parent)
            edit.setCompleter(completer)
            return edit
    
    
    def main(args):
        app = QtGui.QApplication(args)
    
        w = QtGui.QTableWidget(4, 4)
        delegate = CompleterItemDelegate(w)
        w.setItemDelegate(delegate)
        w.show()
    
        ret = app.exec_()
        return ret
    
    
    if __name__ == "__main__":
        import sys
    
        sys.exit(main(sys.argv))