Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Overriding QCompleter popup position



  • I've asked on Stackoverflow so maybe this is bad form but i'm not getting any response there so hoping someone can help here.

    There have been similar questions asked about overriding the QCompleter popup position but i'll still not found a working solution. I simply want to move the popup down around 5px (I have some specific styling requirements)

    I've tried subclassing a QListView and using that as my popup using setPopup(). I then override the showEvent and move the popup down in Y. I also do this on the resizeEvent since I believe this is triggered when items are filtered and the popup resizes. However this doesn't work.. I then used a singleshot timer to trigger the move after 1ms. This does kind of work but it seems quite inconsistent - the first time it shows is different to subsequent times or resizing.

    Below is my latest attempt (trying to hack it by counting the number of popups..), hopefully someone can show me what i'm doing wrong or a better solution

    import sys
    import os
    from PySide2 import QtCore, QtWidgets, QtGui
    
    class QPopup(QtWidgets.QListView):
        def __init__(self, parent=None):
            super(QPopup, self).__init__(parent)
    
            self.popups = 0
    
        def offset(self):
            y = 3 if self.popups < 2 else 7
            print('y: {}'.format(y))
            self.move(self.pos().x(), self.pos().y() + y)
    
            self.popups += 1
    
        def showEvent(self, event):
            print('show')
            # self.offset()
            QtCore.QTimer.singleShot(1, self.offset)
    
        def resizeEvent(self, event):
            print('resize')
            # self.offset()
            QtCore.QTimer.singleShot(1, self.offset)
    
    class MyDialog(QtWidgets.QDialog):
        def __init__(self, parent=None):
            super(MyDialog, self).__init__(parent)
    
            self.create_widgets()
            self.create_layout()
            self.create_connections()
    
        def create_widgets(self):
            self.le = QtWidgets.QLineEdit('')
    
            self.completer = QtWidgets.QCompleter(self)
            self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
            self.completer.setCompletionMode(QtWidgets.QCompleter.PopupCompletion)
            self.completer.setMaxVisibleItems(10)
            self.completer.setFilterMode(QtCore.Qt.MatchContains)
            self.completer.setPopup(QPopup())
    
            popup = QPopup(self)
            self.completer.setPopup(popup)
    
            self.model = QtCore.QStringListModel()
            self.completer.setModel(self.model)
    
            self.le.setCompleter(self.completer)
    
            self.completer.model().setStringList(['one','two','three'])
    
        def create_layout(self):
            main_layout = QtWidgets.QVBoxLayout(self)
    
            main_layout.addWidget(self.le)
    
        def create_connections(self):
            pass
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
    
        my_dialog = MyDialog()
    
        my_dialog.show()  # Show the UI
        sys.exit(app.exec_())
    

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You might have a starting point with this stack overflow answer.


Log in to reply