QtableWidget 表头设置复选框及添加按键标签

        为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对象的值。

通过上述步骤,我们成功实现了以下功能:

  1. 自定义表头:通过继承 QHeaderView 并重写 paintSection 方法,在表头中绘制了一个复选框。
  2. 信号与槽机制:当表头复选框状态改变时,触发信号更新表格中所有行的复选框状态。
  3. 单元格操作:为每一行添加了可点击的按钮,支持删除行等操作。

希望这篇博客对你有所帮助!如果有任何问题或改进建议,请随时反馈。       

  四、示例下载

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值