Sunday 18 October 2020

Overriding QCompleter popup position

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_())


from Overriding QCompleter popup position

No comments:

Post a Comment