问题描述
我有一个重新实现的comboBox,可以执行动态搜索和自动补全(代码不是我的)。问题是当我键入的内容与组合框列表中的任何值都不匹配并按Enter时-我收到一个空字符串。但是我希望收到一个旧值,该值在我开始键入其他值之前在组合框中。有人可以帮我吗?
我还要询问ExtendedComboBox
类中2个字符串的含义(只要代码不是我的):
- 函数
on_completer_activated
中有表达式if text:
;我不明白这是什么意思,因为我总是写整个表达式(例如if text == True:
或类似的东西) - 我不理解
self.activated[str].emit(self.itemText(index))
行中[str]的含义。当信号后直接出现方括号中的内容时,我在pyqt
中从未见过这种构造。
代码:
from PyQt5 import QtCore,QtGui,QtWidgets
import sys
class ExtendedComboBox(QtWidgets.QComboBox):
def __init__(self,parent=None):
super(ExtendedComboBox,self).__init__(parent)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.setEditable(True)
# add a filter model to filter matching items
self.pFilterModel = QtCore.QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
# add a completer,which uses the filter model
self.completer = QtWidgets.QCompleter(self.pFilterModel,self)
# always show all (filtered) completions
self.completer.setCompletionMode(QtWidgets.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)
class ComboBox_Model(QtCore.QAbstractListModel):
def __init__(self,data_list = [],parent = None):
super(ComboBox_Model,self).__init__()
self.data_list = data_list
def rowCount(self,parent):
return len(self.data_list)
def data(self,index,role):
if role == QtCore.Qt.displayRole:
row = index.row()
value = self.data_list[row]
return value
if role == QtCore.Qt.EditRole:
row = index.row()
value = self.data_list[row]
return value
class Mainwindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.comboBox = ExtendedComboBox()
self.layout_1 = QtWidgets.QHBoxLayout()
self.layout_1.addWidget(self.comboBox)
self.setLayout(self.layout_1)
data = ['some text to display','other text to display','different text']
self.model = ComboBox_Model(data)
self.comboBox.setModel(self.model)
if __name__ == '__main__':
app = QtWidgets.QApplication([])
application = Mainwindow()
application.show()
sys.exit(app.exec())
解决方法
将组合框设置为可编辑时,默认情况下,按回车键时允许在当前模型的底部插入不存在的项目。由于该代码中使用的模型不可编辑,因此在按回车键输入无法识别的文本时,组合框无法添加新项目(并选择该项目),从而将索引设置为-1。
您可以连接到嵌入式QLineEdit returnPressed
信号并检查当前索引是否有效;之所以可能这样做,是因为该信号先前也已连接到组合框插入,因此,当您收到该信号时,组合已经尝试添加新项并最终设置(可能是)无效索引。
要存储先前的索引,只需连接到currentIndexChanged()
并保存它,只要它大于或等于0。
class ExtendedComboBox(QtWidgets.QComboBox):
def __init__(self,parent=None):
# ...
self.lineEdit().returnPressed.connect(self.returnPressed)
self.currentIndexChanged.connect(self.storePreviousIndex)
self.previousIndex = self.currentIndex()
def storePreviousIndex(self,index):
if index >= 0:
self.previousIndex = index
def returnPressed(self):
if self.currentIndex() < 0 or self.currentText() != self.itemText(self.currentIndex()):
self.setCurrentIndex(self.previousIndex)
请注意,returnPressed
中的第二个比较是为了增加对默认内部模型的兼容性,以防未调用setModel()
并且插入策略为NoInsert
的情况。
关于最后两个问题:
-
if
语句检查条件是否为真,或者,如果需要,条件为 not false ,例如“不是什么” “(又名False,0,无);您可以使用简单的语句进行一些实验以更好地理解:if True:
,if 1:
,if 'something':
都将成为有效条件,而if False:
,if 0:
或{ {1}}不是。 - 某些信号的自变量具有多个签名,这意味着同一信号可以多次发出,每次使用不同类型的自变量;例如,QComboBox的
if '':
信号被发射两次,第一次以activated
的形式使用新的当前索引,然后是新的当前文本。每当您要连接(或发出)不是默认值的过载时,都需要在方括号中指定签名。在上述情况下,仅显式发出int
签名的信号(不过,我不知道为什么str
不是这样)。请注意,在Qt中逐渐消除了过载信号(实际上,从Qt 5.14开始,int
的{{1}}签名被认为已经过时了。)