1

Long story short, I already have the things that I need to display (for a qlineedit) in a list. But there are some additional information that I need to display in the auto-complete box, that messes up the QCompleter since I use its setModel method to update what it displays (so the additional information that I put into the setModel method messes with the completion rule of the QCompleter) So I need a QCompleter-like display underneath a QLineEdit. Is there anyway I can make that happen?

#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)
4

1 回答 1

0

A suitable solution is to create a custom model that has roles for each manufacturer, model number and description, so you can use the completionRole property of QCompleter and only filter it by model number.

By default the selected role text is displayed, so that we do not have that inappropriate behavior we will overwrite pathFromIndex() to return the Qt::DisplayRole role:

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": "StackOverFlow", "modelNumber": "STANDOFF100", "description": "description"})
    model.addProduct({"manufacturer": "StarTech", "modelNumber": "ABCSTANDOFF122", "description": "description"})
    model.addProduct({"manufacturer": "StarTrek", "modelNumber": "ABCSTANDOFF111", "description": "description"})
    model.addProduct({"manufacturer": "StackOverFlow", "modelNumber": "DFSTANDOFF100", "description": "description"})

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

    le.show()
    sys.exit(app.exec_())
于 2018-01-18T22:13:42.963 回答