QCompleter 的值列表稍后可以在 pyqt5 中再次修改/更新吗?



我正在使用Pyqt5制作GUI,其中有5个Qlineedit字段。

每个值的范围可以说[1 -5]。如果用户尝试选择第三个Qlineedit字段并选择了值'2'。其他字段的范围现在应该是而不是包含'2'

同样,如果他选择了另一个值为'4'的字段,则其余字段应该只有[1,3,5]作为可用选项。

(请记住,用户也可以删除任何字段中的值,可用值应相应更新)

我试图使用列表和更新QCompleter的字段,只要我看到任何textChanged信号。

下面的代码工作完美,除非当用户让说之前在某些字段中输入'14',现在试图使用退格删除它。'4'将被删除,但删除'1'时,它将崩溃,没有任何回溯。

"进程结束,退出代码-1073741819 (0xC0000005)">

如果我在删除'1'之前点击lineedit字段,它工作得很好。

最小代码-

#!/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()

正如我在评论中指出的那样,如果您想限制用户可以选择的值,那么使用QLineEdit不是一个合适的小部件。在本例中,由于用户有多个选项,那么合适的小部件是QComboBox。要进行过滤,您可以使用覆盖filterAcceptsRow方法的QSortFilterProxyModel来实现自定义逻辑。

#!/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()

实现这一点的正确方法是使用带有QCompleter的模型。模型可以随着时间的推移改变它的内容,而补全器将对它做出相应的反应。

在您的例子中,您可以首先创建一个包含所有可能值的模型。然后,你可以使用QSortFilterProxyModel,根据你当前的UI状态,它可以减少集合。代理模型是您在QCompleter中使用的模型。

这个(否则不相关)问题是实现这样一个代理模型的示例Python代码:QSortFilterProxyModel不应用大小写不敏感

最新更新