我希望有一个简单的列标题,其中包含一个复选框,用于选择/取消选择QTableView中的所有行.单击标题中的复选框会导致选择或取消选择所有行.

当我想在表格单元格中添加一个复选框时,我必须在数据(..)中返回Qt :: CheckStateRole的检查状态,以获得所需的模型索引,如下所示.这是按预期工作的.
QVariant MyModel::data( const QModelIndex & rIndex, int iRole) const
{
...
if (iRole == Qt::Qt::CheckStateRole)
{
return checkstate;
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我想在标题单元格中添加一个复选框时,上述方法无效.听到我的示例代码.
QVariant MyModel::headerData( int iSection, Qt::Orientation eOrientation, int iRole) const
{
...
if (iRole == Qt::CheckStateRole)
{
return checkstate;
}
}
Run Code Online (Sandbox Code Playgroud)
QTableView不使用Qt :: CheckStateRole调用我的模型中的headerData()函数,就像使用data()函数一样.
为什么会这样?如何通过仅修改自定义表模型在标题单元格中插入复选框?
(我不想为此目的创建自定义QTableView或QHeaderView)
我很惊讶这样一个hacky解决方案被推荐和使用。
第一:检查状态应该存储在模型中。所有的工具都已经在那里了。
bool MyModel::setHeaderData(int index, Qt::Orientation orient, const QVariant& val, int role)
{
if(Qt::Vertical != orient)
return Base::setHeaderData(index, orient, val, role);
storeCheckState(index, val);
emit headerDataChanged(orient, index, index);
return true;
}
QVariant MyModel::headerData(int index, Qt::Orientation o, int role) const
{
if(Qt::Vertical != orient)
return Base::headerData(index, o, role);
switch(role)
{
...
case Qt::CheckStateRole:
return fetchCheckState(index);
}
return Base::headerData(index, o, role);
}
Run Code Online (Sandbox Code Playgroud)
第二:我们只需处理标题上的点击信号即可切换选中状态。
connect(header, &QHeaderView::sectionClicked, receiver
, [receiver](int sec)
{
const auto index = logicalIndex(sec);
model()->setHeaderData(index
, Qt::Vertical
, Qt::CheckState(model()->headerData(index, Qt::Vertical, Qt::CheckStateRole).toUInt()) != Qt::Checked ? Qt::Checked : Qt::Unchecked
, Qt::CheckStateRole);
});
Run Code Online (Sandbox Code Playgroud)
第三:
此时我们已经有了完整的功能检查行为,唯一缺少的部分是可视化。最明智的方法是再次使用该模型,利用Qt::DecorationRole. 这是一个虚拟实现:
QVariant MyModel::headerData(int index, Qt::Orientation o, int role) const
{
if(Qt::Vertical != orient)
return Base::headerData(index, o, role);
switch(role)
{
case Qt::DecorationRole:
{
QPixmap p{12,12};
p.fill(Qt::CheckState(headerData(index, o, Qt::CheckStateRole).toUInt()) ? Qt::green : Qt::red);
return p;
}
break;
...
}
return Base::headerData(index, o, role);
}
Run Code Online (Sandbox Code Playgroud)
当然,可以使用样式图在此处绘制一个真正的复选框。
请注意,此解决方案不需要子类化和自定义小部件。
此外,检查状态与视图/UI 分离。唯一的缺点是视觉效果是由模型处理的,但这是可选的 - 可以使用任何方式来绘制检查状态,包括来自替代答案的方法。
您无法做到-默认情况下,Qt不支持标题中的复选框。您可以阅读https://wiki.qt.io/Qt_project_org_faq#How_can_I_insert_a_checkbox_into_the_header_of_my_view.3F了解更多信息,以及如何使用自定义实现QHeaderView
这是已接受答案中链接中的一些修改/修复(复选框显示为禁用且重绘不起作用)代码。
。H
class CheckBoxHeader : public QHeaderView
{
Q_OBJECT
public:
CheckBoxHeader(Qt::Orientation orientation, QWidget* parent = 0);
bool isChecked() const { return isChecked_; }
void setIsChecked(bool val);
signals:
void checkBoxClicked(bool state);
protected:
void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const;
void mousePressEvent(QMouseEvent* event);
private:
bool isChecked_;
void redrawCheckBox();
};
Run Code Online (Sandbox Code Playgroud)
.cpp
#include "CheckBoxHeader.h"
CheckBoxHeader::CheckBoxHeader(Qt::Orientation orientation, QWidget* parent /*= 0*/)
: QHeaderView(orientation, parent)
{
isChecked_ = true;
}
void CheckBoxHeader::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
if (logicalIndex == 0)
{
QStyleOptionButton option;
option.rect = QRect(1,3,20,20);
option.state = QStyle::State_Enabled | QStyle::State_Active;
if (isChecked_)
option.state |= QStyle::State_On;
else
option.state |= QStyle::State_Off;
option.state |= QStyle::State_Off;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
}
}
void CheckBoxHeader::mousePressEvent(QMouseEvent* event)
{
setIsChecked(!isChecked());
emit checkBoxClicked(isChecked());
}
void CheckBoxHeader::redrawCheckBox()
{
viewport()->update();
}
void CheckBoxHeader::setIsChecked(bool val)
{
if (isChecked_ != val)
{
isChecked_ = val;
redrawCheckBox();
}
}
Run Code Online (Sandbox Code Playgroud)
用法
CheckBoxHeader* header = new CheckBoxHeader(Qt::Horizontal, &table);
table.setHorizontalHeader(header);
// handle signal if needed (to set checkboxes in all rows, etc.)
//connect(header, &CheckBoxHeader::checkBoxClicked, this, &MyForm::on_header_checkBoxClicked);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8324 次 |
| 最近记录: |