【问题标题】:Qt Custom Multi-Select QComboBox from SQL Model来自 SQL 模型的 Qt 自定义多选 QComboBox
【发布时间】:2018-10-28 15:03:01
【问题描述】:

我想要一个下拉类别选择框,它允许用户单击多个选择,并且最好连接到 SQL 查询。我并没有特别关注组合框(每次点击时消失没有帮助),无论什么都能完成工作。

目前,我基本上已经将那个杰里装配在一起,它在技术上允许多个选择,但它只是基于随机鼠标是否被拖动到它上面。

self.catbx=QComboBox()
...
self.catq=QtSql.QSqlQuery(conn)
self.catq.exec("SELECT name FROM categories")
self.catmo=QtSql.QSqlQueryModel()
self.catmo.setQuery(self.catq)
self.catbx.setModel(self.catmo)
...
self.catview=QListView()
self.catview.setModel(self.catmo)
self.catbx.setView(self.catview)
self.catview.setSelectionMode(QAbstractItemView.MultiSelection)

希望这足够清楚,有人可以提供帮助! :)

【问题讨论】:

  • 你想要一个带有复选框的组合框吗?
  • 复选框列表带有一个按钮,该按钮控制列表在按钮下的显示/隐藏?!
  • @DmitrySazonov 没关系,只要它没有在每次点击时消失!甚至只是一个可检查项目的组合框
  • @user26472 您希望弹出窗口关闭什么事件?
  • @eyllanesc 不完全确定你在问什么,但我想要的是一个弹出“类别选择”菜单,它将附加到我的应用程序主表的过滤器上。有相当多的类别可供选择(多选),所以我想要 qcombobox 的下拉功能,它有一个窗口,只有当用户点击它外面时它才会消失,它会过滤数据。清楚吗?

标签: python pyqt pyqt5 qcombobox qsqlquerymodel


【解决方案1】:

基本上是项目不可选择,因为这是触发关闭弹出窗口的事件,因此解决方案是像我在previous answer 中所做的那样消除模型中的该标志。

另一方面,QSqlQueryModel 中默认不提供可检查选项,因此我们必须基于另一个 previous answer 来实现它。

最后,创建了一个继承自QComboBox 的类,我们覆盖hidePopup() 方法以发出发送所选项目的信号。

更新:

如果您想在您按下项目的任何部分时也被标记,您必须创建一个委托并覆盖editorEvent() 方法,以便它处理MouseButtonRelease 事件。但这带来了一个小问题:要打开弹出窗口,您必须按下显示的项目,以便标记打开。

from PyQt5 import QtCore, QtGui, QtWidgets, QtSql

class CheckSqlQueryModel(QtSql.QSqlQueryModel):
    def __init__(self, *args, **kwargs):
        QtSql.QSqlQueryModel.__init__(self, *args, **kwargs)
        self.checks = {}

    def checkState(self, pindex):
        if pindex not in self.checks.keys():
            self.checks[pindex] = QtCore.Qt.Unchecked
        return self.checks[pindex]

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.CheckStateRole and index.isValid():
            return self.checkState(QtCore.QPersistentModelIndex(index))
        return QtSql.QSqlQueryModel.data(self, index, role)

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.CheckStateRole and index.isValid():
            self.checks[QtCore.QPersistentModelIndex(index)] = value
            return True
        return QtSql.QSqlQueryModel(self, index, value, role)

    def flags(self, index):
        fl = QtSql.QSqlQueryModel.flags(self, index) & ~QtCore.Qt.ItemIsSelectable 
        fl |= QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable
        return fl

class CheckComboBox(QtWidgets.QComboBox):
    selectedChanged = QtCore.pyqtSignal(list)

    def hidePopup(self):
        results = []
        for i in range(self.count()):
            if self.itemData(i, QtCore.Qt.CheckStateRole) == QtCore.Qt.Checked:
                results.append(self.itemText(i))
        self.selectedChanged.emit(results)
        QtWidgets.QComboBox.hidePopup(self)

class CheckDelegate(QtWidgets.QStyledItemDelegate):
    def editorEvent(self, event, model, option, index):
        if event.type() == QtCore.QEvent.MouseButtonRelease:
            val = index.data(QtCore.Qt.CheckStateRole)
            new_val = QtCore.Qt.Checked if val == QtCore.Qt.Unchecked else QtCore.Qt.Unchecked
            model.setData(index, new_val, QtCore.Qt.CheckStateRole)
            return True
        return QtWidgets.QStyledItemDelegate.editorEvent(self, event, model, option, index)


class Widget(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        QtWidgets.QWidget.__init__(self, *args, **kwargs)
        lay = QtWidgets.QVBoxLayout(self)

        combo = CheckComboBox()
        combo.setView(QtWidgets.QListView())
        combo.setItemDelegate(CheckDelegate(combo))
        model = CheckSqlQueryModel()
        model.setQuery("SELECT name FROM categories")
        combo.setModel(model)

        self.lw = QtWidgets.QListWidget()
        combo.selectedChanged.connect(self.on_selectedChanged)

        lay.addWidget(combo)
        lay.addWidget(self.lw)

    def on_selectedChanged(self, items):
        self.lw.clear()
        self.lw.addItems(items)

def createConnection():
    db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName(":memory:")
    if not db.open():
        QtWidgets.QMessageBox.critical(None, "Cannot open database",
                             "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
    query = QtSql.QSqlQuery()
    query.exec_("create table categories (id int primary key, name varchar(20))");
    for i in range(1, 10):
         query.exec_("insert into categories values({i}, 'categories-{i}')".format(i=i));

    return True

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    if not createConnection():
        sys.exit(-1)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

【讨论】:

  • 谢谢!!有什么方法可以点击标签名称来计算复选框吗?我试着弄乱旗帜和东西,但没有运气。除此之外,虽然它现在可以正常工作了,谢谢:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-06
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-28
相关资源
最近更新 更多