Можно ли иметь внешний вид, подобный QCompleter, без использования QCompleter?

Короче говоря, у меня уже есть вещи, которые мне нужно отобразить (для qlineedit) в списке. Но есть некоторая дополнительная информация, которую мне нужно отобразить в поле автозаполнения, которая искажает QCompleter, поскольку я использую его метод setModel для обновления того, что он отображает (поэтому дополнительная информация, которую я помещаю в метод setModel, мешает завершению правило QCompleter) Поэтому мне нужен QCompleter-подобный дисплей под QLineEdit. В любом случае я могу это сделать?

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

person Community    schedule 18.01.2018    source источник
comment
объясните лучше, я не понимаю, чего вы хотите, было бы очень полезно, если бы вы одобрили изображение, указывающее, что вы хотите.   -  person eyllanesc    schedule 18.01.2018
comment
Вы имеете в виду всплывающее окно, которое отображается с помощью QCompleter? Вы хотите показать что-то похожее на то, что SO предлагает для тегов? QCompleter не является виджетом.   -  person eyllanesc    schedule 18.01.2018
comment
Извините, я не ясно, это просто трудно объяснить. Как вы можете видеть на картинке, которую я привел выше, есть больше продуктов, которые начинаются с Sta, чем тот, который на самом деле показан в коробке. Однако это единственное, что показано на коробке, потому что его производитель также начинается с Sta. Мне нужно, чтобы QCompleter игнорировал первое слово в списке строк, который я предоставляю.   -  person    schedule 19.01.2018
comment
Вы можете показать код, который воспроизводит вашу ошибку, чтобы лучше понять вас, это то, что я называю минимально воспроизводимым примером   -  person eyllanesc    schedule 19.01.2018
comment
Каждый элемент списка, который вы передаете в QCompleter, имеет только 2 слова?, и вы хотите, чтобы я отфильтровал его только по второму слову?   -  person eyllanesc    schedule 19.01.2018
comment
Элемент списка содержит много слов, но название элемента гарантированно будет вторым словом в списке, так как первое слово — производитель, а третье слово — начало описания. Я хочу, чтобы он автоматически завершал только второе слово и игнорировал первое слово, при этом отображая все (производитель, название элемента, описание) внутри поля автозаполнения.   -  person    schedule 19.01.2018
comment
Согласно тому, что я прочитал в каждом предложении на три части: производитель - номер модели - описание, какую из этих частей вы хотите использовать для флитро?, только номер модели, или номер модели и описание.   -  person eyllanesc    schedule 19.01.2018
comment
Только номер модели.   -  person    schedule 19.01.2018
comment
попробуйте с моим ответом.   -  person eyllanesc    schedule 19.01.2018


Ответы (1)


Подходящим решением является создание пользовательской модели с ролями для каждого производителя, номером модели и описанием, чтобы вы могли использовать свойство completionRole для QCompleter и фильтровать его только по номеру модели.

По умолчанию отображается текст выбранной роли, поэтому, чтобы не было такого ненадлежащего поведения, мы перезапишем pathFromIndex(), чтобы вернуть роль 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": "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_())
person eyllanesc    schedule 18.01.2018
comment
Спасибо за ответ, работает! Чтобы удалить продукт, что мне делать? - person ; 19.01.2018
comment
@Steve Какой параметр вы хотите передать, чтобы удалить продукт? Другими словами, какое из трех полей уникально. - person eyllanesc; 19.01.2018
comment
Мне пришлось бы указать номер модели и производителя, чтобы удалить запись, поскольку номер модели может совпадать. - person ; 19.01.2018