PySide2 自动完成:自定义结果

PySide2 AutoComplete: Customize the Result

我正在使用 QCompleter 在 QLineEdit 小部件上实现自动完成:

from PySide2 import QtGui
from PySide2.QtCore import Qt
from PySide2.QtGui import QStandardItem
from PySide2.QtWidgets import QCompleter, QWidget, QLineEdit, QFormLayout, QApplication


class SuggestionPlaceModel(QtGui.QStandardItemModel):

    def __init__(self, parent=None):
        super(SuggestionPlaceModel, self).__init__(parent)

    def search(self, text):
        self.clear()
        data = [{'text': f"{text} {i}"} for i in range(10)]
        for i, row in enumerate(data):
            item = QStandardItem(row['text'])
            self.appendRow(item)


class Completer(QCompleter):

    def splitPath(self, path):
        self.model().search(path)
        return super(Completer, self).splitPath(path)


class Widget(QWidget):

    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self._model = SuggestionPlaceModel(self)
        completer = Completer(self)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        completer.setModel(self._model)
        lineedit = QLineEdit()
        lineedit.setCompleter(completer)
        lay = QFormLayout(self)
        lay.addRow("Location: ", lineedit)


if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

结果如下:

问题:如何自定义 SuggestionPlaceModel class 以便搜索结果可以包括图标、水平分隔符、不同的字体、不同的字体大小等?

一个可能的解决方案是在设置图标的地方使用自定义委托,在这种情况下html您可以使用支持富文本的QLabel。

import random
from PySide2 import QtCore, QtGui, QtWidgets


class Delegate(QtWidgets.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super(Delegate, self).initStyleOption(option, index)
        option.text = ""

    def paint(self, painter, option, index):
        if isinstance(option.widget, QtWidgets.QAbstractItemView):
            option.widget.openPersistentEditor(index)
        super(Delegate, self).paint(painter, option, index)

    def createEditor(self, parent, option, index):
        editor = QtWidgets.QLabel(index.data(), parent)
        editor.setContentsMargins(0, 0, 0, 0)
        editor.setText(index.data(QtCore.Qt.UserRole))
        return editor


class SuggestionPlaceModel(QtGui.QStandardItemModel):
    def search(self, text):
        self.clear()
        for i in range(10):
            html = f"{text}-{i} <b>Stack</b> <i>Overflow</i>"
            plain = QtGui.QTextDocumentFragment.fromHtml(html).toPlainText()
            pixmap = QtGui.QPixmap(128, 128)
            pixmap.fill(QtGui.QColor(*random.sample(range(255), 4)))
            item = QtGui.QStandardItem(plain)
            item.setData(html, QtCore.Qt.UserRole)
            item.setIcon(QtGui.QIcon(pixmap))
            self.appendRow(item)


class Completer(QtWidgets.QCompleter):
    def splitPath(self, path):
        self.model().search(path)
        return super(Completer, self).splitPath(path)


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self._model = SuggestionPlaceModel(self)
        completer = Completer(self)
        completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
        completer.setModel(self._model)
        delegate = Delegate(completer.popup())
        completer.popup().setItemDelegate(delegate)

        lineedit = QtWidgets.QLineEdit()
        lineedit.setCompleter(completer)
        lay = QtWidgets.QFormLayout(self)
        lay.addRow("Location: ", lineedit)


if __name__ == "__main__":

    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())