python GUI autocomplete by key value - python

I am trying to create an autocomplete GUI in python such that as I type a first name, I see possible last names. For example, let's say I have this dictionary: {"George": ["Washington", "Bush"]}. When I start typing "G", I want it to show "Washington" and "Bush". When "Washington" is selected, I want "Washington" to show. I am new to GUIs and I think PyQt has an example of autocompletion, but the words are not in key value pairs but a list of words.
https://wiki.python.org/moin/PyQt/Adding%20auto-completion%20to%20a%20QLineEdit
Is there a way to edit the code in the link so that I can enable this feature? Thank you!

You have to override the pathFromIndex method so that when you select some text, the appropriate option is written in the QLineEdit, and to change what is shown in the popup a delegate should be used.
from PyQt5 import QtCore, QtGui, QtWidgets
def create_model(d):
model = QtGui.QStandardItemModel()
for key, value in d.items():
for val in value:
it = QtGui.QStandardItem(key)
it.setData(val, QtCore.Qt.UserRole)
model.appendRow(it)
return model
class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super(StyledItemDelegate, self).initStyleOption(option, index)
option.text = index.data(QtCore.Qt.UserRole)
class Completer(QtWidgets.QCompleter):
def __init__(self, parent=None):
super(Completer, self).__init__(parent)
QtCore.QTimer.singleShot(0, self.change_delegate)
#QtCore.pyqtSlot()
def change_delegate(self):
delegate = StyledItemDelegate(self)
self.popup().setItemDelegate(delegate)
def pathFromIndex(self, index):
return index.data(QtCore.Qt.UserRole)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
d = {
"George": ["Washington", "Bush"],
"Languages": ["Python", "C++"]
}
model = create_model(d)
w = QtWidgets.QLineEdit()
completer = Completer(w)
completer.setModel(model)
w.setCompleter(completer)
w.show()
sys.exit(app.exec_())

Related

Data will not save when using ComboBoxes inside QTableWidget

import sys
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QApplication, QItemDelegate, QWidget, QTableWidget, QTableWidgetItem, QPushButton, QHeaderView, QHBoxLayout, QVBoxLayout
from PyQt6.QtCore import Qt
import pandas as pd
class ComboBoxDelegate(QItemDelegate):
def __init__(self, parent=None):
super(ComboBoxDelegate, self).__init__(parent)
self.items = []
def setItems(self, items):
self.items = items
def createEditor(self, widget, option, index):
editor = QtWidgets.QComboBox(widget)
editor.addItems(self.items)
return editor
def setEditorData(self, editor, index):
value = index.model().data(index, Qt.ItemDataRole.EditRole)
if value:
editor.setCurrentText(str(value))
print("Data Changed")
def setModelData(self, editor, model, index):
model.setData(index, editor.currentIndex(), Qt.ItemDataRole.EditRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.window_width, self.window_height = 700, 500
self.resize(self.window_width, self.window_height)
self.setWindowTitle('Load Excel (or CSV) data to QTableWidget')
layout = QVBoxLayout()
self.setLayout(layout)
self.table = QTableWidget()
layout.addWidget(self.table)
self.button = QPushButton('&Load Data')
self.button.clicked.connect(lambda _, xl_path=excel_file_path,: self.loadExcelData(xl_path))
layout.addWidget(self.button)
def loadExcelData(self, excel_file_dir):
df = pd.read_csv(excel_file_dir)
if df.size == 0:
return
df.fillna('', inplace=True)
self.table.setRowCount(df.shape[0])
self.table.setColumnCount(df.shape[1])
self.table.setHorizontalHeaderLabels(df.columns)
# returns pandas array object
for row in df.iterrows():
values = row[1]
for col_index, value in enumerate(values):
if isinstance(value, (float, int)):
value = '{0:0,.0f}'.format(value)
tableItem = QTableWidgetItem(str(value))
self.table.setItem(row[0], col_index, tableItem)
self.create_delegate(self.table)
self.table.setColumnWidth(2, 300)
def create_delegate(self, table):
test_del = ComboBoxDelegate()
test_list = ["Gravity Main", "Manhole", "Lateral"]
test_del.setItems(test_list)
table.setItemDelegateForColumn(0, test_del)
if __name__ == '__main__':
excel_file_path = "[Your CSV]"
app = QApplication(sys.argv)
app.setStyleSheet('''
QWidget {
font-size: 17px;
}
''')
myApp = MyApp()
myApp.show()
try:
sys.exit(app.exec())
except SystemExit:
print('Closing Window...')
Extension to previous question
Change the file directory to a random csv.
This populates the QTableWidget and does the same thing as my main program.
The QTableWidget does not save the changes.
My goal is to be able to populate multiple columns with different options based on the csv that is loaded. I had a working version but using QTableView instead of QTableWidget and I am working on transferring that progress.
The issue is caused by a code generation bug, according to the PyQt maintainer.
It should have been fixed in the following PyQt6 snapshots, so it's very likely that if you do a pip update you'll get the working version already, otherwise wait a couple of days and keep an eye on the changelog of the official site.

Can QCompleter's list of values be modified/updated later again in pyqt5?

I am making a GUI using Pyqt5 where there are 5 Qlineedit fields.
The range of values for each can be say [1 -5]. If the user tried to select third Qlineedit field and selected the value '2'. The other fields range should now not include '2' in it.
Similarly if he selected another field with value '4', the remaining fields should have only [1, 3, 5] as available options.
(Please bear in mind that user can delete the value in any field too and available values should be updated accordingly.)
I tried to use list and update QCompleter for the fields as soon as I see any textChanged signal.
The below code works perfectly except when the user lets say had given the input '14' in some field before and now tries to delete it using backspace. '4' will get deleted but on deleting '1' it will crash without any backtrace.
"Process finished with exit code -1073741819 (0xC0000005)"
If I click on the lineedit field before deleting '1', it works fine.
Minimal code -
#!/usr/bin/env python
import logging
import sys
import traceback
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLineEdit, QApplication, QCompleter
class MyWidget(QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
vbox = QVBoxLayout(self)
self.setLayout(vbox)
self.names = ['11', '12', '13', '14', '15']
self.names.sort()
self.line_edits_list = [0]*5
for i in range(len(self.names)):
self.line_edits_list[i] = QLineEdit(self)
completer = QCompleter(self.names, self.line_edits_list[i])
self.line_edits_list[i].setCompleter(completer)
vbox.addWidget(self.line_edits_list[i])
self.line_edits_list[i].textEdited.connect(self.text_changed)
def text_changed(self, text):
names_sel = []
# Check if current text matches anything in our list, if it does add it to a new list
for i in range(len(self.line_edits_list)):
if self.line_edits_list[i].text() in self.names and self.line_edits_list[i].text() not in names_sel:
names_sel.append(self.line_edits_list[i].text())
# The remaining textfields should get their qcompleter ranges updated with unique values of the two lists
for i in range(len(self.line_edits_list)):
if self.line_edits_list[i].text() not in self.names:
try:
new_range = list((set(self.names) - set(names_sel)))
completer = QCompleter(new_range, self.line_edits_list[i])
self.line_edits_list[i].setCompleter(completer)
except:
print(traceback.format_exc())
def test():
app = QApplication(sys.argv)
w = MyWidget()
w.show()
app.exec_()
print("END")
if __name__ == '__main__':
test()
As I pointed out in the comments, using QLineEdit is not a suitable widget if you want to restrict the values that the user can select. In this case, as the user has multiple options, then a suitable widget is the QComboBox. To do the filtering you can use QSortFilterProxyModel overriding the filterAcceptsRow method to implement custom logic.
#!/usr/bin/env python
import sys
from PyQt5.QtCore import QSortFilterProxyModel
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import QApplication, QComboBox, QVBoxLayout, QWidget
class ProxyModel(QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self._hide_items = []
#property
def hide_items(self):
return self._hide_items
#hide_items.setter
def hide_items(self, items):
self._hide_items = items
self.invalidateFilter()
def filterAcceptsRow(self, sourceRow, sourceParent):
index = self.sourceModel().index(sourceRow, 0, sourceParent)
return index.data() not in self.hide_items
class MyWidget(QWidget):
def __init__(self, names, parent=None):
super(MyWidget, self).__init__(parent)
self._comboboxes = []
model = QStandardItemModel()
vbox = QVBoxLayout(self)
for name in names:
model.appendRow(QStandardItem(name))
proxy_model = ProxyModel()
proxy_model.setSourceModel(model)
combobox = QComboBox()
combobox.setModel(proxy_model)
vbox.addWidget(combobox)
combobox.setCurrentIndex(-1)
combobox.currentIndexChanged.connect(self.handle_currentIndexChanged)
self.comboboxes.append(combobox)
self.resize(640, 480)
#property
def comboboxes(self):
return self._comboboxes
def handle_currentIndexChanged(self):
rows = []
for combobox in self.comboboxes:
if combobox.currentIndex() != -1:
rows.append(combobox.currentText())
for i, combobox in enumerate(self.comboboxes):
index = combobox.currentIndex()
proxy_model = combobox.model()
r = rows[:]
if index != -1:
text = combobox.currentText()
if text in r:
r.remove(text)
combobox.blockSignals(True)
proxy_model.hide_items = r
combobox.blockSignals(False)
def test():
app = QApplication(sys.argv)
names = ["11", "12", "13", "14", "15"]
w = MyWidget(names)
w.show()
app.exec_()
if __name__ == "__main__":
test()
The correct way to implement this is by using a model with the QCompleter. The model can change its content over time and the completer will react to it accordingly.
In your case, you could create a model that contains all possible values first. Then, you could use a QSortFilterProxyModel, which, given you current UI state, could reduce the set. The proxy model is the one that you use with QCompleter.
This (otherwise unrelated) question is example Python code for implementing such a proxy model: QSortFilterProxyModel does not apply Caseinsensitive

How to customize Qtreewidget item editor in PyQt5?

I am making a QtreeWidget with item editable,but the problem is with the Item Editor or QAbstractItemDelegate(might be called like this,not sure).I am unable to change the stylesheet,actually i dont know how to do this.And also i want the selected lines(blue in editor) should be according to my wish.like below picture
here i want that blue selected line upto ".jpg",so that anyone cant change that ".jpg". Only ,one can change upto this".jpg"
Here is my code:
import sys
from PyQt5 import QtCore, QtWidgets
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.button = QtWidgets.QPushButton('Edit')
self.button.clicked.connect(self.edittreeitem)
self.tree = QtWidgets.QTreeWidget()
self.tree.setStyleSheet('background:#333333;color:grey')
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tree)
layout.addWidget(self.button)
columns = 'ABCDE'
self.tree.setColumnCount(len(columns))
for index in range(50):
item=QtWidgets.QTreeWidgetItem(
self.tree, [f'{char}{index:02}.jpg' for char in columns])
item.setFlags(item.flags()|QtCore.Qt.ItemIsEditable)
def edittreeitem(self):
getSelected = self.tree.selectedItems()
self.tree.editItem(getSelected[0],0)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('Test')
window.setGeometry(800, 100, 540, 300)
window.show()
sys.exit(app.exec_())
You can create your own delegate that only considers the base name without the extension, and then set the data using the existing extension.
class BaseNameDelegate(QtWidgets.QStyledItemDelegate):
def setEditorData(self, editor, index):
editor.setText(QtCore.QFileInfo(index.data()).completeBaseName())
def setModelData(self, editor, model, index):
name = editor.text()
if not name:
return
suffix = QtCore.QFileInfo(index.data()).suffix()
model.setData(index, '{}.{}'.format(name, suffix))
class Window(QtWidgets.QWidget):
def __init__(self):
# ...
self.tree.setItemDelegate(BaseNameDelegate(self.tree))
The only drawback of this is that the extension is not visible during editing, but that would require an implementation that is a bit more complex than that, as QLineEdit (the default editor for string values of a delegate) doesn't provide such behavior.

How to get a Custom QCompleter to work with a custom item delegate?

I have a custom qcompleter (to match any part of the string) and a custom QStyledItemDelegate (to show different formatting on the drop down options returned by the qcompleter) applied to a QLineEdit, and they both work individually however the QStyledItemDelegate doesn't work when I apply them both.
import sys
from PySide2.QtWidgets import QApplication, QMainWindow, QLineEdit, QCompleter, QStyledItemDelegate
from PySide2.QtCore import Qt, QSortFilterProxyModel, QStringListModel
from PySide2.QtGui import QColor, QPalette
Qcompleter Item delegate:
class CompleterItemDelegate(QStyledItemDelegate):
def initStyleOption(self, option, index):
super(CompleterItemDelegate, self).initStyleOption(option, index)
option.backgroundBrush = QColor("red")
option.palette.setBrush(QPalette.Text, QColor("blue"))
option.displayAlignment = Qt.AlignCenter
Custom QCompleter:
class CustomQCompleter(QCompleter):
def __init__(self, parent=None):
super(CustomQCompleter, self).__init__(parent)
self.local_completion_prefix = ""
self.source_model = None
def setModel(self, model):
self.source_model = model
super(CustomQCompleter, self).setModel(self.source_model)
def updateModel(self):
local_completion_prefix = self.local_completion_prefix
class InnerProxyModel(QSortFilterProxyModel):
def filterAcceptsRow(self, sourceRow, sourceParent):
index0 = self.sourceModel().index(sourceRow, 0, sourceParent)
searchStr = local_completion_prefix.lower()
searchStr_list = searchStr.split()
modelStr = self.sourceModel().data(index0,Qt.DisplayRole).lower()
for string in searchStr_list:
if not string in modelStr:
return False
return True
proxy_model = InnerProxyModel()
proxy_model.setSourceModel(self.source_model)
super(CustomQCompleter, self).setModel(proxy_model)
def splitPath(self, path):
self.local_completion_prefix = str(path)
self.updateModel()
return ""
Main:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
model = QStringListModel()
model.setStringList(['Tom', 'Tommy Stevens', 'Steven'])
# ITEM DELEGATE ONLY - WORKS
# completer = QCompleter()
# completer.setModel(model)
# delegate = CompleterDelegate()
# completer.popup().setItemDelegate(delegate)
# QCOMPLETER DELEGATE ONLY - WORKS
# completer = CustomQCompleter(self)
# completer.setModel(model)
# ITEM DELEGATE AND QCOMPLETER DELEGATE - ITEM DELEGATE DOESNT WORK
completer = CustomQCompleter(self)
completer.setModel(model)
delegate = CompleterItemDelegate()
completer.popup().setItemDelegate(delegate)
self.lineEdit = QLineEdit()
self.lineEdit.setCompleter(completer)
self.setCentralWidget(self.lineEdit)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
p = MainWindow()
p.show()
sys.exit(app.exec_())
Is there a way to make this code work?
Is there a better way to achieve both choosing the completion rules for the qcompleter and formatting the popup results?
Setting the delegate on the popup won't work if the model is set afterwards, since setModel() also calls setPopup(), which in turn sets a new item delegate.
So, you either:
ensure that you set the delegate after setting the model on the completer;
subclass the completer and override setModel(), by calling the base implementation and then restore the delegate, or complete() by restoring the delegate before the base implementation call; note that this won't work in your case because you called the base implementation in updateModel() which will clearly ignore the override;
Moving
delegate = CompleterItemDelegate()
self.popup().setItemDelegate(delegate)
into the CustomQCompleter updateModel function solves the problem as pointed out by musicamante.

How do I Filter the PyQt QCombobox Items based on the text input?

I need a QCombox which Items are filtered based on the text input. If I set the QCombobox editable, the user can insert text and the QCompleter is automatically created. But the items are not filtered and I don’t want the user to add new Items.
Is there any possibility to add this functionality to the QCombobox?
Try this code, is something i used in a project of mine
import sys
from PyQt4.QtGui import QComboBox, QApplication, QCompleter, QSortFilterProxyModel, QStandardItemModel, QStandardItem
from PyQt4.QtCore import Qt
class ExtendedCombo( QComboBox ):
def __init__( self, parent = None):
super( ExtendedCombo, self ).__init__( parent )
self.setFocusPolicy( Qt.StrongFocus )
self.setEditable( True )
self.completer = QCompleter( self )
# always show all completions
self.completer.setCompletionMode( QCompleter.UnfilteredPopupCompletion )
self.pFilterModel = QSortFilterProxyModel( self )
self.pFilterModel.setFilterCaseSensitivity( Qt.CaseInsensitive )
self.completer.setPopup( self.view() )
self.setCompleter( self.completer )
self.lineEdit().textEdited[unicode].connect( self.pFilterModel.setFilterFixedString )
self.completer.activated.connect(self.setTextIfCompleterIsClicked)
def setModel( self, model ):
super(ExtendedCombo, self).setModel( model )
self.pFilterModel.setSourceModel( model )
self.completer.setModel(self.pFilterModel)
def setModelColumn( self, column ):
self.completer.setCompletionColumn( column )
self.pFilterModel.setFilterKeyColumn( column )
super(ExtendedCombo, self).setModelColumn( column )
def view( self ):
return self.completer.popup()
def index( self ):
return self.currentIndex()
def setTextIfCompleterIsClicked(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)
if __name__ == "__main__":
app = QApplication(sys.argv)
model = QStandardItemModel()
for i,word in enumerate( ['hola', 'adios', 'hello', 'good bye'] ):
item = QStandardItem(word)
model.setItem(i, 0, item)
combo = ExtendedCombo()
combo.setModel(model)
combo.setModelColumn(0)
combo.show()
sys.exit(app.exec_())
searching inside the combobox. Finally a good solution. Thank you guys!! It helped me a lot.
And here is the adjusted code to PyQt5:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtWidgets import QCompleter, QComboBox
class ExtendedComboBox(QComboBox):
def __init__(self, parent=None):
super(ExtendedComboBox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
# add a filter model to filter matching items
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# add a completer, which uses the filter model
self.completer = QCompleter(self.pFilterModel, self)
# always show all (filtered) completions
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)
# connect signals
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)
# on selection of an item from the completer, select the corresponding item from combobox
def on_completer_activated(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)
self.activated[str].emit(self.itemText(index))
# on model change, update the models of the filter and completer as well
def setModel(self, model):
super(ExtendedComboBox, self).setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)
# on model column change, update the model column of the filter and completer as well
def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super(ExtendedComboBox, self).setModelColumn(column)
if __name__ == "__main__":
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QStringListModel
app = QApplication(sys.argv)
string_list = ['hola muchachos', 'adios amigos', 'hello world', 'good bye']
combo = ExtendedComboBox()
# either fill the standard model of the combobox
combo.addItems(string_list)
# or use another model
#combo.setModel(QStringListModel(string_list))
combo.resize(300, 40)
combo.show()
sys.exit(app.exec_())
Thanks for the nice answer, I had the same problem.
It works nicely, but forces you to supply an external model, which is unnecessary.
I extended the code to also work with the internal standard model already supplied by the combobox.
Also some cleanup and documentation has been done...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QCompleter, QComboBox, QSortFilterProxyModel
class ExtendedComboBox(QComboBox):
def __init__(self, parent=None):
super(ExtendedComboBox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
# add a filter model to filter matching items
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# add a completer, which uses the filter model
self.completer = QCompleter(self.pFilterModel, self)
# always show all (filtered) completions
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)
# connect signals
self.lineEdit().textEdited[unicode].connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)
# on selection of an item from the completer, select the corresponding item from combobox
def on_completer_activated(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)
# on model change, update the models of the filter and completer as well
def setModel(self, model):
super(ExtendedComboBox, self).setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)
# on model column change, update the model column of the filter and completer as well
def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super(ExtendedComboBox, self).setModelColumn(column)
if __name__ == "__main__":
import sys
from PyQt4.QtGui import QStringListModel, QApplication
app = QApplication(sys.argv)
string_list = ['hola muchachos', 'adios amigos', 'hello world', 'good bye']
combo = ExtendedComboBox()
# either fill the standard model of the combobox
combo.addItems(string_list)
# or use another model
#combo.setModel(QStringListModel(string_list))
combo.resize(300, 40)
combo.show()
sys.exit(app.exec_())
Both answers posted are correct, however they have a small bug wherein filtering the options in the combobox by typing then clicking a selection doesn't cause an activation signal to fire. You can fix this by placing self.activated[str].emit(self.itemText(index)) in on_completer_activated, on the line after self.setCurrentIndex(index).
This fires an activated signal when you select an item from the completer, which contains the name of the item that was clicked.
if someone is interested: the same code for pyqt5
#!/usr/bin/python
import sys
from PyQt5.QtWidgets import QComboBox, QApplication, QCompleter
from PyQt5.QtCore import QSortFilterProxyModel, Qt
from PyQt5.Qt import QStringListModel
class ExtendedComboBox(QComboBox):
def __init__(self, parent=None):
super(ExtendedComboBox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
# add a filter model to filter matching items
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# add a completer, which uses the filter model
self.completer = QCompleter(self.pFilterModel, self)
# always show all (filtered) completions
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.setCompleter(self.completer)
# connect signals
self.lineEdit().textEdited[str].connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)
# on selection of an item from the completer, select the corresponding item from combobox
def on_completer_activated(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)
self.activated[str].emit(self.itemText(index))
# on model change, update the models of the filter and completer as well
def setModel(self, model):
super(ExtendedComboBox, self).setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)
# on model column change, update the model column of the filter and completer as well
def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super(ExtendedComboBox, self).setModelColumn(column)
if __name__ == "__main__":
app = QApplication(sys.argv)
string_list = ['hola muchachos', 'adios amigos', 'hello world', 'good bye']
combo = ExtendedComboBox()
# either fill the standard model of the combobox
combo.addItems(string_list)
# or use another model
#combo.setModel(QStringListModel(string_list))
combo.resize(300, 40)
combo.show()
sys.exit(app.exec_())
It's very easy.
index = your_combo.findText(searched_word, Qt.MatchFixedString)
if index >= 0:
your_combo.setCurrentIndex(index)
You can also use Qt.MatchContain method.
visit https://doc.qt.io/qt-6/qt.html for more details.

Categories