0

我正在用 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
4

1 回答 1

0

如果没有您提供 MCVE,很难分析问题出在哪里,因此我的回复在不考虑您当前代码的情况下实现了您的要求,因为它必须满足以下要求:

  • 您必须有 2 个表:相关的对象和历史。
  • 表objects保存了过滤历史的名字,和你使用的objectName类似,但是一般2个widget可以访问相同的历史,如果连接建立相同的名字
  • 在历史表中,保存了与对象表的 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_())
于 2019-03-24T00:58:38.457 回答