Sophus
Sophus

Reputation: 491

PyQt4: Avoid adding the items to the QComboBox()

Well in the following executable source code you can see that I am working with QCompleter - combined with QComboBox().

Following situation: Imagine you are about to type any random letters that aren't present in the current list and then press Enter. You do this procedure several times in succession. Now click on QComboBox() and you will see that the wildly entered characters are in the QComboBox(). I don't want that. How can I prevent this? Why? I just want to work with the data from the list. The user types a few letters, the word he is looking for. But I don't want a new word in the QComboBox() when the user press Enter.

# -*- coding: cp1252 -*-
import sys

from PyQt4.QtCore import Qt, QVariant, SIGNAL, QEvent
from PyQt4.QtGui import QApplication, QStandardItemModel, QStandardItem, QTreeView, QComboBox, QDialog, \
                         QVBoxLayout, QPushButton, QAbstractItemView, QCompleter, QSortFilterProxyModel, \
                         QKeyEvent

class MyCustomDialog(QDialog):
    def __init__(self, app=None, parent=None):
        QDialog.__init__(self, parent)

        self.app = app

        # Second, we need our QTreeView() and
        # the settings
        self.init_tree_view()

        # Create an empty model for the TreeViews' data
        _standard_item_model = QStandardItemModel(0,2)

       # Add some textual items
        self.food_list = [
                    ["0", 'Cookie dough'], 
                    ["1", 'Hummus'], 
                    ["2", 'Spaghetti'], 
                    ["3", 'Dal makhani'],
                    ["6", 'Blolonese'], 
                    ["4", 'Hachfleisch'], 
                    ["3", 'Nudeln'],
                    ["666", 'Flösch'],
                    ["4", 'Chocolate whipped cream'] 
                ]
        # Now its time to populate data
        self.populate(model=_standard_item_model)

        # Apply the model to the list view
        self.set_tree_view_model(_standard_item_model)

        # QComboBox() will be created 
        self.combo_box = QComboBox(self)

        self.init_complete(model=_standard_item_model)

        # layout is a defined QVBoxLayout()
        layout = QVBoxLayout(self)
        layout.addWidget(self.combo_box)
        self.setLayout(layout)

    def init_tree_view(self):
        self.tree_view = QTreeView()
        self.tree_view.setRootIsDecorated(False)
        self.tree_view.setWordWrap(True)

        self.tree_view.setAlternatingRowColors(True)

        self.tree_view.setSelectionMode(QTreeView.ExtendedSelection)

        self.tree_view.header().hide()

        self.tree_me = QTreeView()
        self.tree_me.setRootIsDecorated(False)
        self.tree_me.setWordWrap(True)
        self.tree_me.setAlternatingRowColors(True)

        self.tree_me.setSelectionMode(QTreeView.ExtendedSelection)

        self.tree_me.header().hide()

    def init_complete(self, model=None):

        # add a completer, which uses the filter model
        # add a filter model to filter matching items
        filterModel = QSortFilterProxyModel(self.combo_box)
        filterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        filterModel.setSourceModel(model)
        filterModel.setFilterKeyColumn(0)

        completer = QCompleter(self.combo_box)

        # Set the model that the QCompleter uses
        # on model column change, update the model
        # column of the filter and completer as well
        completer.setModel(filterModel)
        completer.setCompletionColumn(0)
        completer.popup().installEventFilter(self)
        completer.popup().selectionModel().selectionChanged.connect(lambda new_index:
                    self.get_id_tree_view(new_index=new_index))

        # always show all (filtered) completions
        completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)

        completer.setPopup( self.tree_me )

        self.tree_me.setColumnHidden(1, True)

        self.combo_box.setEditable(True)
        self.combo_box.setCompleter(completer)

        # on model column change, update the model
        # column of the filter and completer as well        
        self.combo_box.setModel(model)
        self.combo_box.setView(self.tree_view)

        # on model column change, update the model column of
        # the filter and completer as well
        self.combo_box.setModelColumn(0)

        self.tree_view.resizeColumnToContents(0)

        self.tree_view.setColumnHidden(1, True)

        if self.combo_box.isEditable():
            self.app.connect(self.combo_box.lineEdit(), SIGNAL('textEdited(QString)'), filterModel.setFilterFixedString)

    def set_tree_view_model(self, model):

        self.tree_view.setModel(model)

    def generator_header_data(self, list_header):

        for header_data in list_header:
            yield header_data

    def set_header_data(self, list_header_data=None, model=None):

        count_column = 0

        for header_data in self.generator_header_data(list_header_data):
            model.setHeaderData(count_column, Qt.Horizontal, header_data)

            count_column +=1 

    def get_id_tree_view(self, new_index=None):

        try:
            if not new_index is None:

                index = new_index.indexes()[1].data()#.toPyObject()

                if isinstance(index, QVariant):
                    print "get_id_tree_view, index", index.toString()

        except IndexError as InErr:
            pass#print "InErr", InErr

    def populate_data_item(self, item_list=None, model=None):

        count_items = len(item_list)

        if count_items == 2:

            item_first, item_second = item_list

        two_columns_item = [QStandardItem(item_second), QStandardItem(str(item_first))]

        model.appendRow(two_columns_item)

    def populate(self, model=None):

        for single_list in self.food_list:
            self.populate_data_item(item_list=single_list, model=model)

def main():
    app = QApplication(sys.argv)
    window = MyCustomDialog(app=app)
    window.resize(300, 50)
    window.show()
    try:
        sip.setdestroyonexit(False)
    except:
        # missing in older versions
        pass
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Upvotes: 2

Views: 868

Answers (1)

vedadev
vedadev

Reputation: 66

http://doc.qt.io/qt-4.8/qcombobox.html#details

When the user enters a new string in an editable combobox, the widget may or may not insert it, and it can insert it in several locations. The default policy is is AtBottom but you can change this using setInsertPolicy().

http://doc.qt.io/qt-4.8/qcombobox.html#insertPolicy-prop

void setInsertPolicy(InsertPolicy policy)

QComboBox::NoInsert - The string will not be inserted into the combobox.

Upvotes: 3

Related Questions