我正在尝试对QLineEdit使用QCompleter类,以便在键入时提供自动完成建议,并在用户输入新文本后更新建议。但是,当我尝试使用以已经在完成者列表中的内容开头的文本更新完成者时,它只会使整个应用程序崩溃,并且没有可见的异常!即使try-except也无法捕获此错误,而且我不明白自己在做什么错...

下面是我的代码的一个简单示例:这是一个简单的“ echo”控制台应用程序,可从QLineEdit(输入文本框)获取命令并将其写入QTextBrowser(输出文本框)。输入全新的“命令”(文本)时,它可以正常工作,并被添加到完成程序中,因此下一次我可以看到它。但是,如果新文本的开始类似于完成列表中的其他单词,则选择它会使整个GUI应用程序崩溃,并且没有可见异常,即使我在调试模式下运行也是如此...

请参见下面的示例,并尝试在上方的文本框中输入以下选项:a,aa,aaa(其开始类似于completer的单词:aaa1)

我究竟做错了什么??

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QVBoxLayout, QLineEdit, QTextBrowser, QCompleter

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.setWindowTitle('console')
        self.setGeometry(10, 50, 500, 800)

        # Create text box for input
        self.consoleCommandLineEdit = QLineEdit(self)
        self.consoleCommandLineEdit.setFixedHeight(25)
        self.consoleCommandLineEdit.editingFinished.connect(self.gotConsoleCommand)
        self.completerCommands = ['aaa1','aaa2','aaa3'] # initial completer list
        completer = QCompleter(self.completerCommands)
        self.consoleCommandLineEdit.setCompleter(completer)

        # Create text box for output
        self.consoleViewer = QTextBrowser(self)
        self.consoleViewer.setLineWrapMode(QTextBrowser.NoWrap)

        widget = QWidget(self)
        self.setCentralWidget(widget)
        self.vlay = QVBoxLayout(widget)
        self.vlay.addWidget(self.consoleCommandLineEdit)
        self.vlay.addWidget(self.consoleViewer)

    def gotConsoleCommand(self):
        cmd = self.consoleCommandLineEdit.text()
        self.consoleCommandLineEdit.setText('')
        self.sendCommandToConsole(cmd)

    def sendCommandToConsole(self,cmd):
        self.consoleViewer.append(cmd) # add cmd to output box
        if cmd not in self.completerCommands: # if the command is new, add it to the completer
            self.completerCommands.append(cmd)                  # 1. add the new text to the list we have
            completer = QCompleter(self.completerCommands)      # 2. create a new completer object
            self.consoleCommandLineEdit.setCompleter(completer) # 3. set the new completer as the LineEdit completer


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit(app.exec_())

最佳答案

我尚未找到问题的原因,但是比每次需要添加新文本时创建新的QCompleter更好的解决方案。在这种情况下,最好使用模型存储作为QCompleter信息基础的文本。

import sys
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import (
    QApplication,
    QWidget,
    QMainWindow,
    QVBoxLayout,
    QLineEdit,
    QTextBrowser,
    QCompleter,
)


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.setWindowTitle("console")
        self.setGeometry(10, 50, 500, 800)

        # Create text box for input
        self.consoleCommandLineEdit = QLineEdit()
        self.consoleCommandLineEdit.setFixedHeight(25)
        self.consoleCommandLineEdit.editingFinished.connect(self.gotConsoleCommand)

        self.model = QStandardItemModel()
        self.model.appendRow([QStandardItem(text) for text in ("aaa1", "aaa2", "aaa3")])
        completer = QCompleter(self.model, self)
        self.consoleCommandLineEdit.setCompleter(completer)

        # Create text box for output
        self.consoleViewer = QTextBrowser(lineWrapMode=QTextBrowser.NoWrap)

        widget = QWidget()
        self.setCentralWidget(widget)
        vlay = QVBoxLayout(widget)
        vlay.addWidget(self.consoleCommandLineEdit)
        vlay.addWidget(self.consoleViewer)

    def gotConsoleCommand(self):
        cmd = self.consoleCommandLineEdit.text()
        self.consoleCommandLineEdit.clear()
        self.sendCommandToConsole(cmd)

    def sendCommandToConsole(self, cmd):
        self.consoleViewer.append(cmd)  # add cmd to output box
        if not self.model.findItems(cmd):
            self.model.appendRow(QStandardItem(cmd))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit(app.exec_())


也许可以帮助我们理解该问题的原因是,如果将父级添加到QCompleter,则不会发生此问题:
completer = QCompleter(self.completerCommands, self)


但我强调:最好的解决方案是使用模型。

10-02 10:37