我正在尝试实现我们可以在小部件/工具/自定义完成器源中找到的QCompleter示例。我想要的是当我键入一些文本时,如果有一些匹配项,则选择可用的第一行完成行,因此如果我按回车键(并且仅当我按下它时(,完成就完成了。
但是在我的代码中,该行从未被选中。我认为我的问题位于keyPressEvent中,但我不知道在哪里。这是一个最小的例子,用pyqt5(5.10(和Python 3.5.2编写。
任何帮助都非常感谢:)
此致敬意
import sys
from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant
from PyQt5.QtWidgets import (QApplication, QCompleter, QItemDelegate,
QLineEdit, QMainWindow, QTableView)
class MyLineEdit(QLineEdit):
def __init__(self, parent=None, completer=None):
super().__init__(parent)
if completer:
self.setCompleter(completer)
def setCompleter(self, completer):
if completer:
completer.setWidget(self)
completer.setCompletionMode(QCompleter.PopupCompletion)
completer.setCaseSensitivity(Qt.CaseInsensitive)
completer.setModelSorting(
QCompleter.CaseSensitivelySortedModel)
completer.setMaxVisibleItems(15)
completer.activated.connect(self.insertCompletion)
super().setCompleter(completer)
def insertCompletion(self, completion):
completer = self.completer()
if completer and completer.widget() == self:
completer.widget().setText(completion)
def keyPressEvent(self, event):
completer = self.completer()
if event.key() in (Qt.Key_Return, Qt.Key_Enter,
Qt.Key_Tab, Qt.Key_Backtab):
self.returnPressed.emit()
if completer and completer.popup().isHidden():
return
super().keyPressEvent(event)
input_text = self.text()
if completer:
if not event.text():
completer.popup().hide()
return
if input_text and input_text != completer.completionPrefix():
completer.setCompletionPrefix(input_text)
completer.popup().setCurrentIndex(
completer.completionModel().index(0, 0))
class MyDelegate(QItemDelegate):
def __init__(self, parent):
super().__init__(parent)
def createEditor(self, parent, option, index):
strings = ('tata', 'tete', 'titi', 'toto', 'tutu')
completer = QCompleter(strings)
editor = MyLineEdit(parent)
editor.setCompleter(completer)
editor.editingFinished.connect(self.commitAndCloseEditor)
editor.returnPressed.connect(self.commitAndCloseEditor)
return editor
def commitAndCloseEditor(self):
editor = self.sender()
self.commitData.emit(editor)
self.closeEditor.emit(editor)
def setEditorData(self, editor, index):
if editor:
editor.setText(index.model().data[0])
def setModelData(self, editor, model, index):
if editor:
model.setData(index, editor.text(), Qt.EditRole)
class Model(QAbstractTableModel):
def __init__(self):
super().__init__()
self.data = ['hello']
def rowCount(self, parent=None):
return 1
def columnCount(self, parent=None):
return 1
def data(self, index, role):
if not index.isValid():
return QVariant()
if role in (Qt.DisplayRole, Qt.EditRole):
return self.data[0]
return QVariant()
def setData(self, index, value, role):
if role == Qt.EditRole:
self.data[0] = value
top_left = self.index(0, 0)
bottom_right = self.index(
self.rowCount() + 1, self.columnCount())
self.dataChanged.emit(top_left, bottom_right,
[Qt.DisplayRole])
return True
return False
def flags(self, index):
return Qt.ItemIsEditable | super().flags(index)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.model = Model()
self.table = QTableView()
self.table.setModel(self.model)
delegate = MyDelegate(self.table)
self.table.setItemDelegateForColumn(0, delegate)
def initUI(self):
self.show()
self.setCentralWidget(self.table)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.initUI()
sys.exit(app.exec_())
试试看:
import sys
from PyQt5 import QtCore, QtWidgets
class LineEdit(QtWidgets.QLineEdit):
def __init__(self, *args, **kwargs):
QtWidgets.QLineEdit.__init__(self, *args, **kwargs)
self.multipleCompleter = None
def keyPressEvent(self, event):
QtWidgets.QLineEdit.keyPressEvent(self, event)
if not self.multipleCompleter:
return
c = self.multipleCompleter
if self.text() == "":
return
c.setCompletionPrefix(self.cursorWord(self.text()))
if len(c.completionPrefix()) < 1:
c.popup().hide()
return
c.complete()
def cursorWord(self, sentence):
p = sentence.rfind(" ")
if p == -1:
return sentence
return sentence[p + 1:]
def insertCompletion(self, text):
p = self.text().rfind(" ")
if p == -1:
self.setText(text)
else:
self.setText(self.text()[:p+1]+ text)
def setMultipleCompleter(self, completer):
self.multipleCompleter = completer
self.multipleCompleter.setWidget(self)
completer.activated.connect(self.insertCompletion)
def main():
app = QtWidgets.QApplication(sys.argv)
w = LineEdit()
completer = QtWidgets.QCompleter(['tata', 'tete', 'titi', 'toto', 'tutu'])
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
w.setMultipleCompleter(completer)
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
终于找到了解决方案。我使用了QTextEdit,它不适用于QLineEdit,我不知道为什么。我仍然有一个小问题,当我点击返回键时无法关闭完成弹出窗口,所以我必须按回车键,两次。问题不大。
import sys
from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, pyqtSignal
from PyQt5.QtGui import QTextCursor, QTextOption
from PyQt5.QtWidgets import (QAbstractItemDelegate, QApplication, QCompleter,
QItemDelegate, QMainWindow, QTableView, QTextEdit)
class MyLineEdit(QTextEdit):
returnPressed = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptRichText(False)
self.setWordWrapMode(QTextOption.NoWrap)
self.setUndoRedoEnabled(False)
self.setTabChangesFocus(True)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.completer = None
self.textChanged.connect(self.textHasChanged)
def setCompleter(self, completer):
if completer:
completer.setWidget(self)
completer.setCompletionMode(QCompleter.PopupCompletion)
completer.setCaseSensitivity(Qt.CaseInsensitive)
completer.setModelSorting(
QCompleter.CaseSensitivelySortedModel)
completer.setMaxVisibleItems(15)
completer.activated.connect(self.insertCompletion)
self.completer = completer
def insertCompletion(self, completion):
print('>>> insertCompletion')
if self.completer and self.completer.widget() == self:
self.completer.widget().setPlainText(completion)
self.completer.widget().moveCursor(QTextCursor.EndOfLine)
self.completer.widget().ensureCursorVisible()
def focusInEvent(self, event):
print('>>> focusInEvent')
if self.completer:
self.completer.setWidget(self)
super().focusInEvent(event)
def keyPressEvent(self, event):
print('>>> keyPressEvent')
if self.completer and self.completer.popup().isVisible():
if event.key() in (Qt.Key_Return, Qt.Key_Enter,
Qt.Key_Tab, Qt.Key_Backtab, Qt.Key_Escape):
event.ignore()
return
else:
if event.key() in(Qt.Key_Return, Qt.Key_Enter):
self.returnPressed.emit()
return
super().keyPressEvent(event)
if not self.toPlainText():
self.completer.popup().hide()
return
self.completer.setCompletionPrefix(self.toPlainText())
self.completer.popup().setCurrentIndex(
self.completer.completionModel().index(0, 0))
self.completer.complete()
def textHasChanged(self):
# remove new lines and strip left blank characters
self.blockSignals(True)
cursor = self.textCursor()
self.setPlainText(' '.join(self.toPlainText().splitlines()).lstrip())
self.setTextCursor(cursor)
self.ensureCursorVisible()
self.blockSignals(False)
class MyDelegate(QItemDelegate):
def __init__(self, parent):
super().__init__(parent)
def createEditor(self, parent, option, index):
strings = ('tata', 'tada', 'tadam', 'tete', 'titi', 'toto', 'tutu')
completer = QCompleter(strings)
editor = MyLineEdit(parent)
editor.setCompleter(completer)
editor.returnPressed.connect(self.commitAndCloseEditor)
return editor
def commitAndCloseEditor(self):
print('>>> commitAndCloseEditor')
editor = self.sender()
self.commitData.emit(editor)
self.closeEditor.emit(editor)
def setEditorData(self, editor, index):
if editor:
editor.setText(index.model().data[0])
editor.selectAll()
def setModelData(self, editor, model, index):
if editor:
model.setData(index, editor.toPlainText(), Qt.EditRole)
class Model(QAbstractTableModel):
def __init__(self):
super().__init__()
self.data = ['hello']
def rowCount(self, parent=None):
return 1
def columnCount(self, parent=None):
return 1
def data(self, index, role):
if not index.isValid():
return QVariant()
if role in (Qt.DisplayRole, Qt.EditRole):
return self.data[0]
return QVariant()
def setData(self, index, value, role):
if role == Qt.EditRole:
self.data[0] = value
top_left = self.index(0, 0)
bottom_right = self.index(
self.rowCount() + 1, self.columnCount())
self.dataChanged.emit(top_left, bottom_right,
[Qt.DisplayRole])
return True
return False
def flags(self, index):
return Qt.ItemIsEditable | super().flags(index)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.model = Model()
self.table = QTableView()
self.table.setModel(self.model)
delegate = MyDelegate(self.table)
self.table.setItemDelegateForColumn(0, delegate)
def initUI(self):
self.show()
self.setCentralWidget(self.table)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.initUI()
sys.exit(app.exec_())