【问题标题】:Multicolumn Model for QCompleterQCompleter 的多列模型
【发布时间】:2020-06-02 22:33:45
【问题描述】:

我正在尝试使用 QCompleter 在 QComboBox 上自动完成。下面的两张图片显示了填充的组合框(左)和第 1 列(右)上的 QCompleter。

只要 QComboBox 和 QCompleter 的模型列相同,此示例就可以正常工作。但是对于这个例子来说,QCompleter 使用第 0 列(城市/州)会更直观,但仍然让 QComboBox 使用第 1 列(机场代码)。代码如下:

from PyQt5.QtCore import pyqtSlot, QObject
from PyQt5.QtWidgets import (QApplication, QMainWindow, QComboBox,
                             QCompleter, QTableView, QLabel)
from PyQt5.QtSql import (QSqlQuery, QSqlQueryModel, QSqlDatabase)
import sys
import sqlite3

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

        self.setGeometry(300, 300, 400, 300)

        fid = open('example.db', 'w')
        fid.close()

        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName('example.db')
        db.open()
        query = QSqlQuery(db)

        query.exec_('CREATE TABLE "airports" ("city" TEXT, "code" TEXT)')

        airports = [('Aberdeen, SD','ABR'), ('Abilene, TX','ABI'),
                    ('Adak Island, AK','ADK'), ('Akiachak, AK','KKI'),
                    ('Akiak, AK','AKI'), ('Akron/Canton, OH','CAK'),
                    ('Akuton, AK','KQA'), ('Alakanuk, AK','AUK'),
                    ('Alamogordo, NM','ALM'), ('Alamosa, CO','ALS'),
                    ('Albany, NY','ALB'), ('Albuquerque, NM','ABQ')]
        for item in airports:
            sql = 'INSERT INTO airports(city, code) VALUES(?, ?)'
            query.prepare(sql)
            query.addBindValue(item[0])
            query.addBindValue(item[1])
            query.exec_()

        query.exec_('SELECT * FROM airports')

        model =  QSqlQueryModel()
        model.setQuery(query)

        self.cb = QComboBox(parent = self)
        self.cb.setModel(model)
        self.cb.setModelColumn(1)
        self.cb.setView(QTableView(self.cb))
        self.cb.setGeometry(50,50, 250, 50)
        self.cb.currentIndexChanged.connect(self.indexer)

        self.label = QLabel(parent = self)
        self.label.setGeometry(20,200, 250, 50)

        self.cb.view().setMinimumWidth(500)
        self.cb.setEditable(True)

        self.completer = QCompleter()
        self.completer.setCaseSensitivity(False)
        self.cb.setCompleter(self.completer)
        self.completer.setModel(model)
        self.completer.setCompletionColumn(1)
        self.completer.setPopup(QTableView())
        self.completer.popup().setMinimumWidth(500)
        self.completer.popup().setMinimumHeight(500)

        self.completer.activated.connect(self.activatedHandler)

    @pyqtSlot(QObject)        
    def activatedHandler(self, arg):
        pass

    def indexer(self, idx):
        self.label.setText('%d' % idx)

app = QApplication(sys.argv)
main = MainWindow(None)
main.show()
sys.exit(app.exec_())

如果我将 QCompleter 更改为使用第 0 列,即

self.completer.setCompletionColumn(0)

然后在完成者完成操作后选择正确的组合框行,但显示的文本是城市/州而不是机场代码(左下方和中间)。此外,如果用户按下回车键,那么组合框会尝试使用文本来选择一行,但找不到它并将组合框行重置为 -1。 (右下)。有什么方法可以改变这种行为,以便在组合框中显示所需的文本(机场代码)?

【问题讨论】:

  • 你能解释一下“输入”吗,我无法复制它
  • 在 Alamoso 的图片中,CO 组合框的光标位于该字符串的末尾。如果您按下回车键,那么组合框会尝试将该文本设置为活动行,但它无法找到它,因为它在不同的列中进行搜索。所以它重置为-1。看起来您的 CustomCompleter 修复了此行为。 :-)
  • 只有在 QCompleter 的弹出窗口中没有选择任何项目并按 Enter 时,我才重现“-1”,在您的图像中选择了一个,所以我得到了选定的行。使用我的解决方案,第二个问题仍然存在吗?
  • @eyllanesc,使用您的解决方案,第二个问题不会持续存在。因为组合框具有来自您的自定义类的正确文本,所以在按下返回后它不会重置。

标签: python pyqt pyqt5 qcompleter


【解决方案1】:

QCompleter默认使用模型completionColumn的文本进行搜索和自动补全,因此存在冲突,可能的解决方案是重写pathFromIndex方法并返回适当的文本

class CustomCompleter(QCompleter):
    def pathFromIndex(self, index):
        sibling_index = index.sibling(index.row(), 1)
        return super().pathFromIndex(sibling_index)
self.completer = CustomCompleter()

我无法重现第二个问题,所以我将等待 OP 反馈。

【讨论】:

  • 不错的解决方案。我永远不会想到从way they describe it in the docs 覆盖 pathFromIndex。所有的路径、角色和其他东西真的很混乱。
  • @bfris 简单来说该方法获取从视图(弹出)中选择的QModelIndex并返回用于“自动完成”的文本,默认情况下它使用completionColumn和角色Qt.EditRole
猜你喜欢
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 1970-01-01
相关资源
最近更新 更多