【问题标题】:How to refresh QTableView when it is driven by model模型驱动时如何刷新QTableView
【发布时间】:2015-02-19 22:14:17
【问题描述】:

下面的代码创建由self.myModel (QAbstractTableModel) 驱动的QTableView。 “显示全部”self.checkBox 链接到 self.myModel.cbChanged() 方法。

问题:如何修改此代码,以便在选中复选框后立即刷新“QTableView”?

目标:当复选框被选中时,我们希望显示奇数项目。以及要隐藏的偶数项。 当复选框关闭(未选中)时,我们希望显示偶数项目。所有奇数项目都被隐藏。

import sys, os
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)      

        self.items=['One','Two','Three','Four','Five','Six','Seven']
        self.cb_status=True

    def rowCount(self, parent=QtCore.QModelIndex()):   
        return len(self.items)
    def columnCount(self, index=QtCore.QModelIndex()):
        return 1

    def data(self, index, role):
        if not index.isValid() or not (0<=index.row()<len(self.items)):
            return QtCore.QVariant()

        item=str(self.items[index.row()])

        if role==QtCore.Qt.DisplayRole and self.cb_status:
            return item
        else:
            return QtCore.QVariant()

    def cbChanged(self, arg=None):
        self.cb_status=arg  

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        mainLayout=QtGui.QHBoxLayout()
        self.setLayout(mainLayout)   

        self.viewA=QtGui.QTableView()
        self.viewA.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch) 

        self.myModel=TableModel()
        self.viewA.setModel(self.myModel)

        self.checkBox=QtGui.QCheckBox("Show All")  
        self.checkBox.stateChanged.connect(self.myModel.cbChanged)
        self.checkBox.setChecked(self.myModel.cb_status)

        mainLayout.addWidget(self.viewA)
        mainLayout.addWidget(self.checkBox)  
        self.show()   

view=Window() 
sys.exit(app.exec_())

【问题讨论】:

  • 在一种情况下设置空模型,在另一种情况下设置数据模型?视图将自动更新。
  • 请举个例子
  • 在使用复选框打开和关闭项目的情况下,分配一个空的“虚拟”模型可能会起作用。但是,如果假设我们想使用复选框在奇数和偶数项目编号之间切换,那么空模型方法将无法解决问题......
  • 我同意我必须更具体地说明需要实现的目标。
  • 回到主题。当我们想要在复选框为ON时显示奇数项目而在复选框为OFF(未选中)时显示偶数项目时,我们应该如何处理?

标签: python qt pyqt pyside qtableview


【解决方案1】:

为此,您可以使用QSortFilterProxyModel 类。这样,我们就不会篡改实际源模型的结构或数据。我们只是将主要源映射到这个代理模型,视图使用它来显示过滤/排序的数据。我们可以随意影响代理模型中的数据,而不会有篡改源模型的风险。

以下是修改后的源代码以使用它:

import sys, os
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)
        self.items=['One','Two','Three','Four','Five','Six','Seven']

    def rowCount(self, parent=QtCore.QModelIndex()):   
        return len(self.items)
    def columnCount(self, index=QtCore.QModelIndex()):
        return 1

    def data(self, index, role):
        if not index.isValid() or not (0<=index.row()<len(self.items)):
            return QtCore.QVariant()

        item=str(self.items[index.row()])

        if role==QtCore.Qt.DisplayRole:
            return item
        else:
            return QtCore.QVariant()


class MySortFilterProxyModel(QtGui.QSortFilterProxyModel):
    def __init__(self):
        super(MySortFilterProxyModel, self).__init__()
        self.cb_status=True

    def cbChanged(self, arg=None):
        self.cb_status=arg
        print self.cb_status
        self.invalidateFilter()

    def filterAcceptsRow(self, sourceRow, sourceParent):
        print_when_odd_flag = self.cb_status
        is_odd = True
        index = self.sourceModel().index(sourceRow, 0, sourceParent)
        print "My Row Data: %s" % self.sourceModel().data(index, role=QtCore.Qt.DisplayRole)

        if (sourceRow + 1) % 2 == 0:
            is_odd = False

        if print_when_odd_flag:
            if is_odd:
                return True
            else:
                return False
        else:
            if not is_odd:
                return True
            else:
                return False


class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        mainLayout=QtGui.QHBoxLayout()
        self.setLayout(mainLayout)   

        self.viewA=QtGui.QTableView()
        self.viewA.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch) 

        self.myModel=TableModel()

        self.sortModel = MySortFilterProxyModel()
        self.sortModel.setSourceModel(self.myModel)

        self.viewA.setModel(self.sortModel)

        self.checkBox=QtGui.QCheckBox("Show All")  
        self.checkBox.stateChanged.connect(self.sortModel.cbChanged)
        self.checkBox.setChecked(self.sortModel.cb_status)

        mainLayout.addWidget(self.viewA)
        mainLayout.addWidget(self.checkBox)  
        self.show()   

view=Window() 
sys.exit(app.exec_())

如您所见,我已从 UI 和主要源模型中删除了所有连接。主源模型不关心复选框是否设置。这使它保持解耦。它更干净。代理模型现在已经被赋予了这个责任。 filterAcceptsRow() 主要根据复选框状态显示的行的索引是奇数还是偶数来显示正确的行。

我已经添加了一些打印语句,以防你想根据数据而不是索引来改变逻辑。

查看QSortFilterProxyModel 和一些examples here 上的文档。

希望这是有用的。

【讨论】:

  • 感谢您的澄清!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多