重写的QHeaderView的点击QCheckBox不刷新问题

表格表头中的QCheckBox单击勾选时无效的问题解决
问题:表格表头设置了checkbox,正常点击应该代表全选。该CheckBox应该变成勾选状态,其下方每一行的CheckBox也应一并勾选成功。现在问题是点击表头的CheckBox无效,CheckBox的状态并没有改变。

解决思路:代码的逻辑是写了一个CHeaderView类继承自QHeaderView类,在该类中重写了mouseReleaseEvent(QMouseEvent*)函数,函数中有一处if语句中调用sectionsClickable()函数判断表头是否是可点击的。通过打断点的方式发现这个函数返回了false,导致程序没有进入到if语句中去重画CheckBox。在外面实例化CHeaderView的地方加上setSectionsClickable(true),但是仍然无效。此时怀疑是代码某些地方调用了setSectionsClickable(false),把表头section可点击状态设置为了false,导致获取到的状态是false。
在代码中全局搜索setSectionsClickable函数,发现并没有地方设置了false。转换思路,怀疑是其他控件重写mouseReleaseEvent(QMouseEvent*)函数导致了某些异常。该表格是用一个CTableView类实现,最上层的父类是QTreeView,走读代码发现没有地方重写mouseReleaseEvent会影响CHeaderView中的该函数。因此必须再次转换思路,继续排查。
注意到其他地方也有类似的表格,只是表格表头和展示内容不同,第一列均是CheckBox,勾选表头的CheckBox,下方每一行均全选,而另外一处的这个表格CheckBox是正常的,勾选时sectionsClickable()返回true,也调用了setSectionsClickable(true)。开始比较两处使用时有什么差异。注意到两个控件都设置了点击表头不能进行排序。但是功能正确的表格是先调用setSortingEnabled(false),后调用setSectionsClickable(true),而此处是反过来调用的。
思考下QT如何实现点击表头不进行排序功能,推测可能会把表头的可点击状态改为false,这样点击时不生效,自然就不会继续排序。为了验证猜想,查看QT源码。查看源码发现QTreeView中的setSortingEnabled函数中会调用其header的setSectionsClickable函数,将其状态置为setSortingEnabled的参数,因此应先设置setSortingEnabled,再调用header的setSectionsClickable把状态设置为true,这样mouseReleaseEvent(QMouseEvent*)函数中的sectionsClickable()返回true,勾选CheckBox生效了,问题解决。

涉及的源码如下:

void QTreeView::setSortingEnabled(bool enable)
{
    Q_D(QTreeView);
    header()->setSortIndicatorShown(enable);
    header()->setSectionsClickable(enable);
    if (enable) {
        //sortByColumn has to be called before we connect or set the sortingEnabled flag
        // because otherwise it will not call sort on the model.
        sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
        connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
                this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection);
    } else {
        disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
                   this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)));
    }
    d->sortingEnabled = enable;
}

解决方法:设置点击表头不能排序和点击表头可改变CheckBox状态时,应先设置setSortingEnabled,再调用header的setSectionsClickable,避免setSortingEnabled的false把setSectionsClickable设置的true给覆盖。
————————————————
版权声明:本文为CSDN博主「Willow 」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43554422/article/details/113643529


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QHeaderView 是 Qt 框架中的表头控件,用于显示表格的列头或行头。默认情况下,QHeaderView 只支持单级表头,即只能显示一行或一列的标题。但是我们可以通过重写 QHeaderView 的 paintSection() 方法来实现多级表头。 具体实现步骤如下: 1. 定义一个类继承自 QHeaderView。 2. 在该类中定义一个数据结构用于存储多级表头的信息,例如每个表头单元格的文本、行列位置等。 3. 重写 paintSection() 方法,在该方法中根据数据结构绘制多级表头。 下面是一个简单的示例代码,实现了一个包含两级表头的 QTableView: ```python class MultiHeaderTableView(QtWidgets.QTableView): def __init__(self, parent=None): super().__init__(parent) self.setHorizontalHeader(MultiHeaderHorizontalHeader(self)) class MultiHeaderHorizontalHeader(QtWidgets.QHeaderView): def __init__(self, parent=None): super().__init__(QtCore.Qt.Horizontal, parent) self.setSectionsClickable(True) self.sectionClicked.connect(self.on_section_clicked) self.levels = [ [('', 0, 0), ('A', 0, 2), ('B', 0, 2)], [('C', 1, 1), ('D', 1, 1)] ] def on_section_clicked(self, index): level = self.get_level(index) if level >= 0: print('clicked on level', level) def get_level(self, section): for i, level in enumerate(self.levels): for j, (text, row, col) in enumerate(level): if col == section: return i return -1 def paintSection(self, painter, rect, logicalIndex): painter.save() level = self.get_level(logicalIndex) if level < 0: super().paintSection(painter, rect, logicalIndex) else: font = painter.font() font.setBold(True) painter.setFont(font) painter.drawText(rect, QtCore.Qt.AlignCenter, self.levels[level][0][0]) painter.restore() painter.drawLine(rect.topRight(), rect.bottomRight()) painter.drawLine(rect.bottomLeft(), rect.bottomRight()) for text, row, col in self.levels[level][1:]: if col == logicalIndex: new_rect = self.sectionViewportPosition(row), rect.y(), self.sectionSize(row), rect.height() self.paintSection(painter, new_rect, row) ``` 在上述代码中,MultiHeaderTableView 类继承自 QTableView,用于展示包含多级表头的表格;MultiHeaderHorizontalHeader 类继承自 QHeaderView,用于实现水平方向的多级表头。 在 MultiHeaderHorizontalHeader 类的构造函数中,我们定义了一个包含两级表头的数据结构 self.levels,其中每个元素都是一个包含多个 tuple 的列表,表示同一级别的多个表头单元格。每个 tuple 包含三个元素,分别是单元格文本、所在行位置和所占列数。 重写的 paintSection() 方法中,我们首先判断当前绘制的表头单元格是否为多级表头的单元格,如果不是则调用父类的 paintSection() 方法进行绘制。如果是多级表头单元格,则绘制单元格文本,并绘制横向和纵向的边框。此时,我们需要递归调用 paintSection() 方法来绘制下一级别的表头单元格。 以上代码只是一个简单的示例,实际的实现可能更加复杂。但是通过重写 QHeaderView 的 paintSection() 方法,我们可以轻松地实现多级表头。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值