禁止用户点击 QTableWidget

Posted

技术标签:

【中文标题】禁止用户点击 QTableWidget【英文标题】:Disable user to click over QTableWidget 【发布时间】:2014-01-08 16:25:54 【问题描述】:

我在某些单元格中有带有 CheckBoxes 的 QTableWidget。我想在我使用表格中的数据时禁用用户在表格单元格上执行鼠标单击(因此他不能更改复选框状态)一段时间。我试过table.setDisabled(1),但这会禁用整个表格,我需要启用滚动。

任何帮助将不胜感激。

编辑 更准确地说:表格中最多可以有 15x3000 个单元格,填充文本(可编辑)、复选框(可选中)、svg 图形(双击时打开其他窗口)或一些自定义小部件(也有可点击或可编辑的部分)。我需要在 1 秒 - 10 秒的时间间隔内禁止用户单击或双击单元格(因此他不能更改其中任何一个)(解决方案必须是快速的,而不是遍历所有项目),但我需要滚动条启用和正常的表可见性。

【问题讨论】:

【参考方案1】:

实现这一点的一种方法是继承 QTableWidgetItem 并重新实现setData 方法。这样,您可以控制项目是否接受某些角色的值。

要控制所有项目的“可检查性”,您可以向子类添加一个类属性,只要将检查状态角色的值传递给 setData,就可以对其进行测试。

下面是子类的样子:

class TableWidgetItem(QtGui.QTableWidgetItem):
    _blocked = True

    @classmethod
    def blocked(cls):
        return cls._checkable

    @classmethod
    def setBlocked(cls, checkable):
        cls._checkable = bool(checkable)

    def setData(self, role, value):
        if role != QtCore.Qt.CheckStateRole or self.checkable():
            QtGui.QTableWidgetItem.setData(self, role, value)

所有项目的“可检查性”将被禁用,如下所示:

    TableWidgetItem.setCheckable(False)

更新

可以通过为单元小部件添加通用包装类来扩展上述想法。

下面的类将阻止对表格小部件项目的文本和检查状态的更改,以及通过event-filter 阻止单元格小部件的一系列键盘和鼠标事件(可以根据需要阻止其他事件)。

需要像这样创建单元格小部件:

    widget = CellWidget(self.table, QtGui.QLineEdit())
    self.table.setCellWidget(row, column, widget)

然后像这样访问:

    widget = self.table.cellWidget().widget()

整个表的阻塞将像这样打开:

    TableWidgetItem.setBlocked(True)
    CellWidget.setBlocked(True)
    # or Blockable.setBlocked(True)

以下是课程:

class Blockable(object):
    _blocked = False

    @classmethod
    def blocked(cls):
        return cls._blocked

    @classmethod
    def setBlocked(cls, blocked):
        cls._blocked = bool(blocked)

class TableWidgetItem(Blockable, QtGui.QTableWidgetItem):
    def setData(self, role, value):
        if (not self.blocked() or (
            role != QtCore.Qt.EditRole and
            role != QtCore.Qt.CheckStateRole)):
            QtGui.QTableWidgetItem.setData(self, role, value)

class CellWidget(Blockable, QtGui.QWidget):
    def __init__(self, parent, widget):
        QtGui.QWidget.__init__(self, parent)
        self._widget = widget
        layout = QtGui.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(widget)
        widget.setParent(self)
        widget.installEventFilter(self)
        if hasattr(widget, 'viewport'):
            widget.viewport().installEventFilter(self)
        widget.show()

    def widget(self):
        return self._widget

    def eventFilter(self, widget, event):
        if self.blocked():
            etype = event.type()
            if (etype == QtCore.QEvent.KeyPress or
                etype == QtCore.QEvent.KeyRelease or
                etype == QtCore.QEvent.MouseButtonPress or
                etype == QtCore.QEvent.MouseButtonRelease or
                etype == QtCore.QEvent.MouseButtonDblClick or
                etype == QtCore.QEvent.ContextMenu or
                etype == QtCore.QEvent.Wheel):
                return True
        return QtGui.QWidget.eventFilter(self, widget, event)

【讨论】:

你好,tnx 回答。 @classmethod 是我刚刚学到的新东西(就像 c++ 中的 static 一样,对吗?),但我认为我不能使用它,因为我有许多不同的单元格(带有文本、带有复选框、带有 svg 图形。 ..)。或者我可以吗? @Aleksandar。 python 中@classmethod@staticmethod 之间的主要区别在于类作为第一个参数传递。由于所有实例都具有相同的类,因此它提供了一种简单的共享状态的机制(并且可能比使用全局变量更好)。至于您的实际问题:我确实想知道您是否使用了单元小部件,这显然会改变规范。我看到你已经编辑了你的问题,但它似乎仍然没有得到充分说明。键盘动作呢?是否仍然可以选择单元格,使用箭头键从一个单元格移动到另一个单元格等...? @Aleksandar。我已经用可能适合您的解决方案更新了我的答案。 再次感谢您的回答。看看你的eventFilter 方法,我还有一个问题:如果可能的话,在表格小部件类中做类似的事情会更简单吗? -当我打电话给myTable.blockEvants()时阻止除QtCore.QEvent.Wheel之外的所有事件 @Aleksandar。阻止表格(及其视口)上的事件将完全阻止编辑单元格,但它根本不会阻止单元格小部件上的事件。您想阻止除滚动之外的所有交互吗?如果是这样,那么您可以使用一个遮罩小部件来覆盖表格的视口并将滚轮事件传递给表格。【参考方案2】:

只需遍历所有 QStandardItems 并更改 flags values 以获取不应更改的项目。 您可以使用标志:Qt::ItemIsEditable 或/和Qt::ItemIsEnabled

【讨论】:

准确地说,PyQt 中没有 Qt::ItemsIsEditable 和 Qt::ItemIEnabled。【参考方案3】:

如果您不想禁用 QCheckBoxes 以外的其他项目,则需要禁用项目本身而不是整个表。详情请看下面的python代码:

'''
    Iterate through all the check boxes in the standard items
    and make sure the enabled flag is cleared so that the items are disabled
'''
for standardItem in standardItems:
    standardItem.setFlags(standardItem.flags() & ~Qt.ItemIsEnabled)

这里可以找到相应的文档:

void QTableWidgetItem::setFlags(Qt::ItemFlags flags)

将项目的标志设置为给定的标志。这些决定是否可以选择或修改项目。

【讨论】:

感谢您的回答。起初我是这么想的,但我的表格最多可以有 15x3000 个单元格,而我想要禁用用户执行点击的时间可能是 1s - 10s,因此遍历所有项目可能需要更多时间(我还需要启用它)。这就是为什么我需要更像table.setDisabled(1) 的东西,但不影响滚动

以上是关于禁止用户点击 QTableWidget的主要内容,如果未能解决你的问题,请参考以下文章

怎么禁止用户点击f12查看数据,查看网页代码,布局样式

如何禁止用户连续点击一个按钮事件详细JS

Vue 利用指令实现禁止反复发送请求

win10系统怎么禁止用户使用电脑和打印机

如何禁止用户调整Winform的大小

禁止用户复制网页内容