我已通读 QCompleter 文档 ( https://doc.qt.io/qt-5/qcompleter.html ),并尝试为 QPlainTextEdit 实现 QCompleter。
现在我已经让它像这样工作了:
但问题是,如果您开始编写由 keywords.kwlist 创建的列表中的单词,那么它会集中在光标下方弹出的弹出窗口上,并且不会让我继续输入。
但是,当在 QCompleter 文档页面上将代码从 C++ 转换为 Python 时,即使它为我提供了下面的单词选择,我仍然可以输入。
我尝试将焦点设置为 self.editor 但这不起作用。我需要有关此问题以及弹出窗口位置的帮助。现在它有点挡住了这个词的视野。
它的功能应该是这样的:
但这仅适用于 QLineEdit。
from PyQt5.QtWidgets import QCompleter, QPlainTextEdit, QApplication, QWidget, QHBoxLayout
import sys
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QTextCursor, QFont, QTextOption
import keyword
class Completer(QCompleter):
insertText = pyqtSignal(str)
def __init__(self, myKeywords=None, parent=None):
myKeywords = keyword.kwlist
QCompleter.__init__(self, myKeywords, parent)
self.activated.connect(self.changeCompletion)
def changeCompletion(self, completion):
if completion.find("(") != -1:
completion = completion[:completion.find("(")]
print(completion)
print("completion is " + str(completion))
self.insertText.emit(completion + " ")
self.popup().hide()
class MyTextEdit(QWidget):
def __init__(self, *args):
super().__init__(*args)
font = QFont()
font.setPointSize(12)
self.editor = QPlainTextEdit()
self.setFont(font)
self.completer = None
self.hbox = QHBoxLayout(self)
self.editor.textChanged.connect(self.complete)
self.hbox.addWidget(self.editor)
def setCompleter(self, completer):
if self.completer:
print("completer is: " + str(completer))
self.disconnect()
if not completer:
print("completer is: " + str(completer))
return
completer.setWidget(self)
completer.setCompletionMode(QCompleter.PopupCompletion)
completer.setCaseSensitivity(Qt.CaseInsensitive)
self.completer = completer
self.completer.insertText.connect(self.insertCompletion)
def insertCompletion(self, completion):
tc = self.editor.textCursor()
extra = (len(completion) - len(self.completer.completionPrefix()))
tc.movePosition(QTextCursor.Left)
tc.movePosition(QTextCursor.EndOfWord)
tc.insertText(completion[-extra:])
self.editor.setTextCursor(tc)
def textUnderCursor(self):
tc = self.editor.textCursor()
tc.select(QTextCursor.WordUnderCursor)
return tc.selectedText()
def complete(self):
completionPrefix = self.textUnderCursor()
print("completion prefix is: " + str(completionPrefix))
self.completer.setCompletionPrefix(completionPrefix)
popup = self.completer.popup()
popup.setCurrentIndex(
self.completer.completionModel().index(0, 0))
cr = self.editor.cursorRect()
cr.setWidth(
self.completer.popup().sizeHintForColumn(0) + self.completer.popup().verticalScrollBar().sizeHint().width())
self.completer.complete(cr)
if __name__ == "__main__":
app = QApplication(sys.argv)
completer = Completer()
te = MyTextEdit()
te.setCompleter(completer)
te.show()
sys.exit(app.exec_())
最佳答案
我意识到答案可能有点晚了,特别是因为用户不再和我们在一起,但供将来引用并作为 pyqt6 实现:
有一个成熟的 C example由Qt提供,我已将其改编为python。 为了在完成弹出窗口弹出后能够继续输入,必须监视按键事件并进行相应的过滤。
请参阅 MyTextEdit 中的 def keyPressEvent[...]
。
import keyword
import sys
from PyQt6 import QtGui
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QTextCursor
from PyQt6.QtWidgets import QApplication, QCompleter, QMainWindow, QPlainTextEdit
class TextEdit(QPlainTextEdit):
"""Custom texteditor."""
def __init__(self):
super().__init__()
completer = QCompleter(keyword.kwlist)
completer.activated.connect(self.insert_completion)
completer.setWidget(self)
completer.setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
self.completer = completer
self.textChanged.connect(self.complete)
def insert_completion(self, completion):
tc = self.textCursor()
extra = len(completion) - len(self.completer.completionPrefix())
tc.movePosition(QTextCursor.MoveOperation.Left)
tc.movePosition(QTextCursor.MoveOperation.EndOfWord)
tc.insertText(completion[-extra:] + " ")
self.setTextCursor(tc)
@property
def text_under_cursor(self):
tc = self.textCursor()
tc.select(QTextCursor.SelectionType.WordUnderCursor)
return tc.selectedText()
def complete(self):
prefix = self.text_under_cursor
self.completer.setCompletionPrefix(prefix)
popup = self.completer.popup()
cr = self.cursorRect()
popup.setCurrentIndex(self.completer.completionModel().index(0, 0))
cr.setWidth(
self.completer.popup().sizeHintForColumn(0)
+ self.completer.popup().verticalScrollBar().sizeHint().width()
)
self.completer.complete(cr)
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
if self.completer.popup().isVisible() and event.key() in [
Qt.Key.Key_Enter,
Qt.Key.Key_Return,
Qt.Key.Key_Up,
Qt.Key.Key_Down,
Qt.Key.Key_Tab,
Qt.Key.Key_Backtab,
]:
event.ignore()
return
super().keyPressEvent(event)
class TextCompleter(QMainWindow):
def __init__(self):
super().__init__()
self.editor = TextEdit()
self.setCentralWidget(self.editor)
if __name__ == "__main__":
app = QApplication([])
te = TextCompleter()
te.show()
sys.exit(app.exec())
关于python - QPlainTextEdit 和 QCompleter 焦点问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51912270/