可以在不使用 QCompleter 的情况下获得类似 QCompleter 的外观吗?

Possible to have a QCompleter-like appearance without using a QCompleter?

长话短说,我已经有了需要在列表中显示(对于 qlineedit)的内容。但是我需要在自动完成框中显示一些附加信息,这会扰乱 QCompleter,因为我使用它的 setModel 方法来更新它显示的内容(所以我放入 setModel 方法的附加信息会扰乱完成QCompleter 的规则)所以我需要在 QLineEdit 下有一个类似 QCompleter 的显示。无论如何我可以做到这一点吗?

#The method TopProducts(text) -> returns a list of strings with the format 
#"manufacturer - model number - description" (picks three products based on the given text)

#in __init__ somewhere:
self.nameEdit = QLineEdit()
self.completer = QCompleter()
self.nameEdit.setCompleter(self.completer)
self.nameEdit.textEdited.connect(self.suggest)
self.model = QStringListModel()

def suggest(self,text):
    stringList = TopProducts(text)
    self.model.setStringList(stringList)
    self.completer.setModel(self.model)

一个合适的解决方案是为每个制造商、型号和描述创建一个自定义模型,这样您就可以使用 completionRole 属性 of QCompleter 并且只过滤它的型号。

默认情况下会显示选定的角色文本,这样我们就不会出现不当行为,我们会将 pathFromIndex() 覆盖为 return Qt::DisplayRole 角色:

class ProductModel(QAbstractListModel):
    ManufacturerRole, ModelNumberRole, DescriptionRole = range(Qt.UserRole, Qt.UserRole + 3)

    def __init__(self, parent=None):
        QAbstractListModel.__init__(self, parent)
        self._products = []

    def addProduct(self, product):
        self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
        self._products.append(product)
        self.endInsertRows()

    def removeProduct(self, model_number, manufacturer):
        selecteds = filter(lambda product: product['manufacturer'] == manufacturer and product["modelNumber"] == model_number, 
            self._products)
        for selected in selecteds:
            row = self._products.index(selected)
            self.beginRemoveRows(QModelIndex(), row, row)
            self._products.pop(row)
            self.endRemoveRows()

    def rowCount(self, parent=QModelIndex()):
        return len(self._products)

    def data(self, index, role=Qt.DisplayRole):
        if 0 <= index.row() < self.rowCount():
            product = self._products[index.row()]
            if role == ProductModel.ManufacturerRole:
                return product["manufacturer"]
            elif role == ProductModel.ModelNumberRole:
                return product["modelNumber"]
            elif role == ProductModel.DescriptionRole:
                return product["description"]
            elif role == Qt.DisplayRole:
                return "{} {} {}".format(*product.values())

class ProductCompler(QCompleter):
    def pathFromIndex(self, index):
        return index.data()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    le = QLineEdit()
    completer = ProductCompler(le)
    le.setCompleter(completer)
    model = ProductModel()
    completer.setModel(model)
    completer.setCompletionRole(ProductModel.ModelNumberRole)

    model.addProduct({"manufacturer": "StarTech", "modelNumber": "STANDOFF122", "description": "description"})
    model.addProduct({"manufacturer": "StarTrek", "modelNumber": "STANDOFF111", "description": "description"})
    model.addProduct({"manufacturer": "Whosebug", "modelNumber": "STANDOFF100", "description": "description"})
    model.addProduct({"manufacturer": "StarTech", "modelNumber": "ABCSTANDOFF122", "description": "description"})
    model.addProduct({"manufacturer": "StarTrek", "modelNumber": "ABCSTANDOFF111", "description": "description"})
    model.addProduct({"manufacturer": "Whosebug", "modelNumber": "DFSTANDOFF100", "description": "description"})

    model.removeProduct("STANDOFF111", "StarTrek")

    le.show()
    sys.exit(app.exec_())