PyQt5 QCompleter для сбоя QLineEdit без видимых исключений - PullRequest
1 голос
/ 24 января 2020

Я пытаюсь использовать класс QCompleter для QLineEdit, чтобы предлагать варианты автозаполнения при вводе текста и обновлять предложения после того, как пользователь вводит новый текст. Но когда я пытаюсь обновить Completer текстом, который начинается с того, что уже находится в списке завершителей, он просто вылетает из приложения без видимых исключений! Даже попытка-исключение не улавливает эту ошибку, и я не могу понять, что я делаю неправильно ...

Ниже приведен более простой пример моего кода: это простое консольное приложение "эхо", которое получает команды из QLineEdit (текстовое поле ввода) и записывает их в QTextBrowser (текстовое поле вывода). При вводе совершенно новой «команды» (текста) она работает нормально и добавляется в завершитель, поэтому в следующий раз я смогу ее увидеть. Но если новый текст начинается аналогично другим словам в полном списке, при его выборе происходит сбой всего приложения GUI без видимых исключений, даже когда я работаю в режиме отладки ...

Пожалуйста, смотрите мой пример ниже, и попробуйте написать в верхнем текстовом поле опции, такие как: a, aa, aaa (которые начинаются аналогично завершению уже слова: 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_())

1 Ответ

1 голос
/ 24 января 2020

Я еще не нашел причину проблемы, но лучшее решение, чем создание нового 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, <b>self</b>)

но я подчеркиваю: лучшее решение - это использовать модель.

...