使用QCompleter时程序退出并出错

问题描述 投票:0回答:1

我正在用pyqt5编写一个程序,并希望通过使用sqlite来存储输入来创建QlineEdit显示历史输入。当focusInEvent发生时我使用一个信号来捕捉光标并选择那时的历史记录,然后我把结果放到QCompleter中,这样它就可以在QlineEdit中弹出。现在我可以在QlineEdit对象中显示历史输入,但是当我点击任何值时,1秒后,整个程序会自动退出并显示错误,其中显示“Python已停止”。

class FocusLineEdit(QLineEdit):
    ac = pyqtSignal(list)
    def __init__(self, parent=None):
        super(FocusLineEdit, self).__init__(parent)
        self.ac.connect(self.addCompleter)

    def focusInEvent(self, event):
        rtl = call_history(self.objectName())
        self.ac.emit(rtl)

    def addCompleter(self, rtl):
        self.autoCompleter = QCompleter(rtl)
        self.autoCompleter.setCompletionMode(1)
        self.setCompleter(self.autoCompleter)

    def focusOutEvent(self, event):
        pass
python pyqt pyqt5 qcompleter
1个回答
0
投票

如果没有提供MCVE,很难分析问题所在,因此我的响应会实现您的需求,而不考虑您当前的代码,因为它必须满足以下要求:

  • 您必须有2个表:相关的对象和历史记录。
  • 表对象保存过滤历史的名称,它类似于您使用的objectName的使用,但通常,如果连接建立相同的名称,则两个小组件可以访问相同的历史记录
  • 在历史表中,保存与对象表的id相关联的单词的信息。

在我的示例中,我使用以下说明创建它们:

CREATE TABLE IF NOT EXISTS objects (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE);
CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, id_object INTEGER REFERENCES objects (id), word TEXT NOT NULL, UNIQUE (id_object, word));

另外为了测试它我创建了一个数据,如果你已经有数据,那么你必须消除if test:和里面的一切。

最后为了更好地理解我的解决方案,我展示了一个根据选择而改变的QTableView。

from PyQt5 import QtCore, QtGui, QtWidgets, QtSql

def createConnection():
    db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
    db_path = 'test.db'
    db.setDatabaseName(db_path)
    if not db.open():
        QMessageBox.critical(None, qApp.tr("Cannot open database"),
                             qApp.tr("Unable to establish a database connection.\n"
                                     "This example needs SQLite support. Please read "
                                     "the Qt SQL driver documentation for information "
                                     "how to build it.\n\n"
                                     "Click Cancel to exit."),
                             QMessageBox.Cancel)
        return False

    test = True
    if test:
        query = QtSql.QSqlQuery()
        if not query.exec_('CREATE TABLE IF NOT EXISTS objects (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE);'):
            return False
        if not query.exec_('CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, id_object INTEGER REFERENCES objects (id), word TEXT NOT NULL, UNIQUE (id_object, word));'):
            return False

        for i in range(3):
            query.prepare('INSERT INTO objects (name) VALUES (?)')
            query.addBindValue("obj{}".format(i))
            if not query.exec_():
                print(query.lastError().text())
        import requests
        import random
        word_site = "http://svnweb.freebsd.org/csrg/share/dict/words?view=co&content-type=text/plain"
        response = requests.get(word_site)
        WORDS = response.content.decode().splitlines()
        print(WORDS)
        for i in range(3):
            for text in random.sample(WORDS, 50):
                query.prepare('INSERT INTO history (id_object, word) VALUES (?, ?)')
                query.addBindValue(i+1)
                query.addBindValue(text)
                if not query.exec_():
                    print(query.lastError().text())
    return True

class Completer(QtWidgets.QCompleter):
    def __init__(self, parent=None):
        super(Completer, self).__init__(parent)
        self._last_words = []

    def splitPath(self, path):
        if path[-1] != ' ':
            words = path.split()
            self._last_words = words[:-1] if len(words) > 1 else []
            return [words[-1]]
        else:
            QtCore.QTimer.singleShot(0, self.popup().hide)
            return []

    def pathFromIndex(self, index):
        val = super(Completer, self).pathFromIndex(index)
        return ' '.join(self._last_words + [val])

class HistoryManager(QtCore.QObject):
    nameChanged = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super(HistoryManager, self).__init__(parent)
        model = QtSql.QSqlRelationalTableModel(self)
        model.setTable("history")
        model.setRelation(1, QtSql.QSqlRelation("objects", "id", "name"))
        model.select()

        self._proxy = QtCore.QSortFilterProxyModel(self)
        self._proxy.setSourceModel(model)
        self._proxy.setFilterKeyColumn(1)
        # proxy.setFilterFixedString("obj1")

        self._widgets = {}
        self._completer = Completer(self)
        self._completer.setModel(self._proxy)
        self._completer.setCompletionColumn(2)

    def register_widget(self, widget, objectname):
        # TODO
        if callable(getattr(widget, "setCompleter")):
            widget.installEventFilter(self)
            self._widgets[widget] = objectname
            return True
        return False

    def eventFilter(self, obj, event):
        if obj in self._widgets:
            if event.type() == QtCore.QEvent.FocusIn:
                name = self._widgets[obj]
                self._proxy.setFilterFixedString(name)
                obj.setCompleter(self._completer)
                self.nameChanged.emit(name)
            elif event.type() == QtCore.QEvent.FocusOut:
                obj.setCompleter(None)
                self._proxy.setFilterFixedString("")
                self.nameChanged.emit("")
        return super(HistoryManager, self).eventFilter(obj, event)

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self._manager = HistoryManager()

        model = QtSql.QSqlRelationalTableModel(self)
        model.setTable("history")
        model.setRelation(1, QtSql.QSqlRelation("objects", "id", "name"))
        model.select()

        self._proxy = QtCore.QSortFilterProxyModel(self)
        self._proxy.setSourceModel(model)
        self._proxy.setFilterKeyColumn(1)

        tv = QtWidgets.QTableView()
        tv.setModel(self._proxy)

        vlay = QtWidgets.QVBoxLayout()
        for i in range(3):
            le = QtWidgets.QLineEdit()
            vlay.addWidget(le)
            self._manager.register_widget(le, "obj{}".format(i))
        vlay.addStretch()
        lay = QtWidgets.QHBoxLayout(self)
        lay.addWidget(tv, stretch=1)
        lay.addLayout(vlay)

        self._manager.nameChanged.connect(self._proxy.setFilterFixedString)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    if not createConnection():
        sys.exit(-1)
    manager = HistoryManager()
    w = Widget()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())
© www.soinside.com 2019 - 2024. All rights reserved.