python - QPlainTextEdit 和 QCompleter 焦点问题

标签 python python-3.x pyqt5 qplaintextedit qcompleter

我已通读 QCompleter 文档 ( https://doc.qt.io/qt-5/qcompleter.html ),并尝试为 QPlainTextEdit 实现 QCompleter。

现在我已经让它像这样工作了:

enter image description here

但问题是,如果您开始编写由 keywords.kwlist 创建的列表中的单词,那么它会集中在光标下方弹出的弹出窗口上,并且不会让我继续输入。

但是,当在 QCompleter 文档页面上将代码从 C++ 转换为 Python 时,即使它为我提供了下面的单词选择,我仍然可以输入。

我尝试将焦点设置为 self.editor 但这不起作用。我需要有关此问题以及弹出窗口位置的帮助。现在它有点挡住了这个词的视野。

它的功能应该是这样的:

enter image description here

但这仅适用于 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[...]

enter image description here

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/

相关文章:

python - PyQT 终端模拟器

python - 用钢笔在 Canvas 上删除

javascript - 在 django 中使用 Datepicker(来自 Jquery)

python - 如何通过 Python 套接字播放 mp3 文件?

python - 根据某些标准查找列表的共同元素?

python - 在 Linux Mint 上安装 pyttsx3

matplotlib - Matplotlib 2.1.0 导航工具栏中的主页按钮嵌入 pyqt5 窗口中,它不再正常工作

python - 如何将嵌套字典转换为 defaultdict?

Python 检查 gzip 存档的完整性

python - 如何从根路径自动重定向?