为QtableWidget 增加一个批量选择的复选框,全选或者全不选。在 Qt 的 QtableWidget 中,默认表头无法直接显示复选框。如果需要在表头中添加一个复选框以实现全选或全不选的功能,则需要自定义表头,可以使用QCheckBox作为表头的widget,并将其放置在QHeaderView中。然后,在表头的widget中,可以使用信号与槽机制来处理复选框的状态变化。
一、简述
QTableWidget表头如果是使用自带的表头则无法通过设置显示出复选框,必须进行自定义表头。
二、效果
最终效果如下:
- 表头第一列显示一个复选框。
- 点击该复选框时,可以实现全选或全不选表格中的所有行。
- 每一行的第一列也包含一个复选框,用于单独选择某一行。
三、代码实现
1、控件实现
ClickedLabel.h
#ifndef CLICKEDLABEL_H
#define CLICKEDLABEL_H
#include <QLabel>
class ClickedLabel : public QLabel
{
Q_OBJECT
public:
ClickedLabel( QWidget* parent = 0);
void mousePressEvent(QMouseEvent *e);//添加鼠标响应事件
void mouseReleaseEvent(QMouseEvent *e);//添加鼠标释放事件
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
signals:
void clicked();//点击信号
private:
int m_iPressed;
};
#endif // CLICKEDLABEL_H
ClickedLabel.cpp
#include "ClickedLabel.h"
ClickedLabel::ClickedLabel(QWidget* parent) : QLabel(parent)
{
setText("详情"); //添加标签默认文本
setAlignment(Qt::AlignCenter); //设置默认对齐方式:中心对齐(居中)
setStyleSheet("color:blue");
m_iPressed = 0;
}
void ClickedLabel::mousePressEvent ( QMouseEvent * e )
{
Q_UNUSED(e);
m_iPressed = 1;
}
void ClickedLabel::mouseReleaseEvent ( QMouseEvent * e )
{
Q_UNUSED(e);
if(m_iPressed)
{
emit clicked();
setStyleSheet("color:gray");
}
}
void ClickedLabel::enterEvent(QEvent *e)
{
Q_UNUSED(e);
setStyleSheet("color:rgb(0,0,0)");
}
void ClickedLabel::leaveEvent(QEvent *e)
{
Q_UNUSED(e);
if(m_iPressed)
{
setStyleSheet("color:gray");
}
else
{
setStyleSheet("color:blue");
}
}
定义一个自定义的 QCheckBoxHeader 类,继承自 QHeaderView。在该类中重写 paintSection() 方法,通过绘制复选框和文本来实现在表头中显示复选框。
checkboxheaderview.h
#ifndef QCHECKBOXHEADERVIEW_H
#define QCHECKBOXHEADERVIEW_H
#include <QCheckBox>
#include <QComboBox>
#include <QHeaderView>
#include <QMap>
class CheckBoxHeaderView : public QHeaderView
{
Q_OBJECT
public:
CheckBoxHeaderView(QMap<int, QString> mapCheckBox, Qt::Orientation orientation, QWidget * parent = 0);
void setCheckBoxState(int logicalIndex,Qt::CheckState state);
protected:
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
Q_SIGNALS:
void stateChanged(QString strHeader,Qt::CheckState state);
private slots:
void checkBox_state_change(int);
private:
QMap<int, QCheckBox*> m_mapCheckBox;
};
#endif // QCHECKBOXHEADERVIEW_H
checkboxheaderview.cpp
#include "checkboxheaderview.h"
CheckBoxHeaderView::CheckBoxHeaderView(QMap<int, QString> mapCheckBox, Qt::Orientation orientation, QWidget* parent)
: QHeaderView(orientation, parent)
{
setStyleSheet("background-color:white;");
for (auto it = mapCheckBox.begin(); it != mapCheckBox.end(); it++)
{
QCheckBox* checkBox = new QCheckBox(it.value(), this);
connect(checkBox, &QCheckBox::stateChanged, this, &CheckBoxHeaderView::checkBox_state_change);
m_mapCheckBox.insert(it.key(), checkBox);
}
setMinimumHeight(40);
}
void CheckBoxHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const
{
auto it = m_mapCheckBox.find(logicalIndex);
if (it == m_mapCheckBox.end())
{
QHeaderView::paintSection(painter, rect, logicalIndex);
return;
}
QCheckBox* checkBox = static_cast<QCheckBox*>(it.value());
if (checkBox != nullptr)
{
QSize sizeCheckBox = checkBox->size();
QRect rcCheckBox;
rcCheckBox.setLeft(rect.left() + 3);
// rcCheckBox.setLeft((rect.right() - rect.left()) / 2 - sizeCheckBox.width() / 2 + rect.left());
rcCheckBox.setTop((rect.bottom() - rect.top()) / 2 - sizeCheckBox.height() / 2 + rect.top());
rcCheckBox.setRight(rcCheckBox.left() + sizeCheckBox.width() - 1);
rcCheckBox.setBottom(rcCheckBox.top() + sizeCheckBox.height() - 1);
checkBox->setGeometry(rcCheckBox);
}
}
void CheckBoxHeaderView::checkBox_state_change(int)
{
QCheckBox *checkBox = dynamic_cast<QCheckBox*>(this->sender());
if (checkBox == nullptr)
return;
emit stateChanged(checkBox->text(),checkBox->checkState());
}
void CheckBoxHeaderView::setCheckBoxState(int logicalIndex,Qt::CheckState state)
{
auto it = m_mapCheckBox.find(logicalIndex);
if (it == m_mapCheckBox.end())
{
return;
}
QCheckBox* checkBox = static_cast<QCheckBox*>(it.value());
checkBox->setCheckState(state);
}
以上代码是一个自定义的表头视图(CheckBoxHeaderView)。在CheckBoxHeaderView中,使用paintSection函数绘制了复选框。
2、控件使用
在主窗口中,创建了一个实例,并在布局中添加该实例。运行程序后,将会显示一个有复选框和按键标签的QTableWidget。
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class CheckBoxHeaderView;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void deleteRow();
void headerStateChanged(QString strHeader,Qt::CheckState state);
private:
Ui::MainWindow *ui;
CheckBoxHeaderView* checkBoxHeaderView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ClickedLabel.h"
#include "checkboxheaderview.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStringList labels;
labels<<QString("序号")<<QString("操作");
ui->tableWidget->setColumnCount(2);
ui->tableWidget->setHorizontalHeaderLabels(labels);
QMap<int, QString> mapCheckBox;
mapCheckBox.insert(0,"序号");
checkBoxHeaderView = new CheckBoxHeaderView(mapCheckBox, Qt::Horizontal, this);
connect(checkBoxHeaderView, &CheckBoxHeaderView::stateChanged, this, &MainWindow::headerStateChanged);
ui->tableWidget->setHorizontalHeader(checkBoxHeaderView);
for (int i = 0; i < 50; i++)
{
ui->tableWidget->insertRow(i);
QTableWidgetItem *item = new QTableWidgetItem(QString("%1").arg(i+1));
item->setCheckState(Qt::CheckState::Unchecked);
ui->tableWidget->setItem(i, 0, item);
ClickedLabel *bt = new ClickedLabel();
QWidget *wgb = new QWidget(this);
QHBoxLayout *verticalLayoutb = new QHBoxLayout(wgb);
verticalLayoutb->setContentsMargins(1,1,1,1);
verticalLayoutb->setSpacing(10);
verticalLayoutb->addStretch();
verticalLayoutb->addWidget(bt);
bt = new ClickedLabel();
bt->setText("删除");
connect(bt,&ClickedLabel::clicked,this,&MainWindow::deleteRow);
verticalLayoutb->addWidget(bt);
verticalLayoutb->addStretch();
ui->tableWidget->setCellWidget(i,1,wgb);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::deleteRow()
{
ClickedLabel *bt = dynamic_cast<ClickedLabel*>(this->sender());
if (bt == nullptr)
return;
int x = bt->parentWidget()->frameGeometry().x();
int y = bt->parentWidget()->frameGeometry().y();
QModelIndex index = ui->tableWidget->indexAt(QPoint(x,y));
ui->tableWidget->removeRow(index.row());
}
void MainWindow::headerStateChanged(QString strHeader,Qt::CheckState state)
{
if(strHeader == "序号")
{
if(state == Qt::Checked)
{
for(int row=0; row<ui->tableWidget->rowCount(); row++)
{
ui->tableWidget->item(row,0)->setCheckState(Qt::Checked);
}
}
else
{
for(int row=0; row<ui->tableWidget->rowCount(); row++)
{
ui->tableWidget->item(row,0)->setCheckState(Qt::Unchecked);
}
}
}
}
总结一下,要在QTableWidget单元格中添加checkbox复选框,需要进行以下操作:
1. 创建一个QTableWidgetItem对象,并设置其文本或图标。
2. 调用TableWidget的setItem()方法,将QTableWidgetItem对象添加到特定单元格中。
3. 调用TableWidget的setCellWidget()方法,将一个QCheckBox对象添加到特定单元格中。
4. 将QTableWidgetItem对象和QCheckBox对象进行连接,以便在QCheckBox对象状态更改时更新QTableWidgetItem对象的值。
通过上述步骤,我们成功实现了以下功能:
- 自定义表头:通过继承
QHeaderView
并重写paintSection
方法,在表头中绘制了一个复选框。 - 信号与槽机制:当表头复选框状态改变时,触发信号更新表格中所有行的复选框状态。
- 单元格操作:为每一行添加了可点击的按钮,支持删除行等操作。
希望这篇博客对你有所帮助!如果有任何问题或改进建议,请随时反馈。
四、示例下载