简体   繁体   English

PyQt QListView 复选框单击切换?

[英]PyQt QListView checkbox click toggle?

I am trying to make a QListView that shows a list of items and whether they're enabled or not.我正在尝试制作一个 QListView 来显示项目列表以及它们是否已启用。 The code below does this, but I also want to be able to toggle the item's enabled state when the user clicks on the checkbox (not just anywhere on the list item, but specifically on the checkbox), how can I do that?下面的代码执行此操作,但我还希望能够在用户单击复选框时切换项目的启用状态(不仅仅是列表项上的任何位置,而是特别是在复选框上),我该怎么做?

在此处输入图片说明

import sys
from dataclasses import dataclass
from typing import Dict, List, Union
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt

@dataclass
class Filter:
    expr: str
    enabled: bool

class Store:
    def __init__(self):
        super().__init__()

        self.filter_viewer: Union["FilterViewer", None] = None
        self.filters: List[Filter] = []

    def update(self):
        if self.filter_viewer is not None:
            self.filter_viewer.list_model.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex())

    def add_filter(self, expr: str, enabled=True):
        filt = Filter(expr=expr, enabled=enabled)
        self.filters.append(filt)
        self.update()

    def remove_filter(self, index: int):
        self.filters.pop(index)
        self.update()

    def toggle_filter(self, index: int):
        self.filters[index].enabled = not self.filters[index].enabled
        self.update()


class FilterViewer(QtWidgets.QWidget):
    def __init__(self, pgdf: Store):
        super().__init__()
        pgdf.filter_viewer = self
        self.pgdf = pgdf


        self.list_view = self.ListView()
        self.list_model = self.ListModel(pgdf)
        self.list_view.setModel(self.list_model)

        self.text_input = QtWidgets.QLineEdit()
        self.submit_button = QtWidgets.QPushButton("Add Filter")

        self.submit_button.clicked.connect(self.add_filter)
        self.text_input.returnPressed.connect(self.add_filter)
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.list_view)
        self.layout.addWidget(self.text_input)
        self.layout.addWidget(self.submit_button)
        self.setLayout(self.layout)

    def add_filter(self):
        expr = self.text_input.text()
        self.text_input.setText("")
        self.pgdf.add_filter(expr=expr)
        print(self.pgdf.filters)


    class ListView(QtWidgets.QListView):
        pass

    class ListModel(QtCore.QAbstractListModel):
        def __init__(self, pgdf: Store):
            super().__init__()
            self.pgdf = pgdf

        def data(self, index: QtCore.QModelIndex, role: int):
            row = index.row()
            if role == Qt.DisplayRole:
                filt = self.pgdf.filters[row]
                return filt.expr

            if role == Qt.CheckStateRole:
                filt = self.pgdf.filters[row]
                if filt.enabled:
                    return Qt.Checked
                else:
                    return Qt.Unchecked

        def rowCount(self, parent):
            return len(self.pgdf.filters)

        def flags(self, index):
            return (QtCore.Qt.ItemIsEnabled |
                    QtCore.Qt.ItemIsUserCheckable)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    pgdf = Store()
    pgdf.add_filter('Generation > 3', enabled=True)
    pgdf.add_filter('Size > 50', enabled=False)
    fv = FilterViewer(pgdf)
    fv.show()
    app.exec_()

The state of the QListView checkboxes is determined by the model, so to change the model information you must override the setData() method: QListView 复选框的状态由模型决定,因此要更改模型信息,您必须覆盖 setData() 方法:

class ListModel(QtCore.QAbstractListModel):
    def __init__(self, pgdf: Store):
        super().__init__()
        self.pgdf = pgdf

    def data(self, index: QtCore.QModelIndex, role: int):
        row = index.row()
        if role == Qt.DisplayRole:
            filt = self.pgdf.filters[row]
            return filt.expr

        if role == Qt.CheckStateRole:
            filt = self.pgdf.filters[row]
            if filt.enabled:
                return Qt.Checked
            else:
                return Qt.Unchecked

    def setData(self, index, value, role=QtCore.Qt.DisplayRole):
        row = index.row()
        if role == Qt.CheckStateRole:
            filt = self.pgdf.filters[row]
            filt.enabled = bool(value)
            self.dataChanged.emit(index, index, (role,))
            return True
        return False

    def rowCount(self, parent):
        return len(self.pgdf.filters)

    def flags(self, index):
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM