首页 > 解决方案 > 如何让自定义 QCompleter 与自定义项目委托一起使用?

问题描述

我有一个自定义 qcompleter(匹配字符串的任何部分)和一个自定义 QStyledItemDelegate(在 qcompleter 返回的下拉选项上显示不同的格式)应用于 QLineEdit,它们都单独工作但是 QStyledItemDelegate 不起作用当我同时应用它们时。

import sys
from PySide2.QtWidgets import QApplication, QMainWindow, QLineEdit, QCompleter, QStyledItemDelegate
from PySide2.QtCore import Qt, QSortFilterProxyModel, QStringListModel
from PySide2.QtGui import QColor, QPalette

Qcompleter 项目委托:

class CompleterItemDelegate(QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(CompleterItemDelegate, self).initStyleOption(option, index)
        option.backgroundBrush = QColor("red")
        option.palette.setBrush(QPalette.Text, QColor("blue"))
        option.displayAlignment = Qt.AlignCenter

自定义 QCompleter:

class CustomQCompleter(QCompleter):
    def __init__(self, parent=None):
        super(CustomQCompleter, self).__init__(parent)
        self.local_completion_prefix = ""
        self.source_model = None

    def setModel(self, model):
        self.source_model = model
        super(CustomQCompleter, self).setModel(self.source_model)

    def updateModel(self):
        local_completion_prefix = self.local_completion_prefix
        class InnerProxyModel(QSortFilterProxyModel):
            def filterAcceptsRow(self, sourceRow, sourceParent):
                index0 = self.sourceModel().index(sourceRow, 0, sourceParent)
                searchStr = local_completion_prefix.lower()
                searchStr_list = searchStr.split()
                modelStr = self.sourceModel().data(index0,Qt.DisplayRole).lower()
                for string in searchStr_list:
                    if not string in modelStr:
                        return False
                return True

        proxy_model = InnerProxyModel()
        proxy_model.setSourceModel(self.source_model)
        super(CustomQCompleter, self).setModel(proxy_model)

    def splitPath(self, path):
        self.local_completion_prefix = str(path)
        self.updateModel()
        return ""

主要的:

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        model = QStringListModel()
        model.setStringList(['Tom', 'Tommy Stevens', 'Steven'])

        # ITEM DELEGATE ONLY - WORKS
        # completer = QCompleter()
        # completer.setModel(model)
        # delegate = CompleterDelegate()
        # completer.popup().setItemDelegate(delegate)

        # QCOMPLETER DELEGATE ONLY - WORKS
        # completer = CustomQCompleter(self)
        # completer.setModel(model)

        # ITEM DELEGATE AND QCOMPLETER DELEGATE - ITEM DELEGATE DOESNT WORK
        completer = CustomQCompleter(self)
        completer.setModel(model)
        delegate = CompleterItemDelegate()
        completer.popup().setItemDelegate(delegate)

        self.lineEdit = QLineEdit()
        self.lineEdit.setCompleter(completer)

        self.setCentralWidget(self.lineEdit)
        self.show()

if __name__ == '__main__':
    app  = QApplication(sys.argv)
    p = MainWindow()
    p.show()
    sys.exit(app.exec_())
  1. 有没有办法让这段代码工作?
  2. 有没有更好的方法来实现为 qcompleter 选择完成规则和格式化弹出结果?

标签: pythonpyside2qlineeditqstyleditemdelegateqcompleter

解决方案


如果模型是在之后设置的,那么在弹出窗口上设置委托将不起作用,因为setModel()还会调用setPopup(),这反过来又会设置一个新的项目委托

所以,你要么:

  • 确保在完成者上设置模型设置委托;
  • setModel()通过调用基本实现然后恢复委托,或complete()通过在基本实现调用之前恢复委托,子类化完成者和覆盖;请注意,这在您的情况下不起作用,因为您调用了基本实现,updateModel()其中显然会忽略覆盖;

推荐阅读