QTableView插入QCheckBox复选框

通过实现QAbstractItemDelegate的paint()函数。
这种方法和《C++_GUI_Qt4_编程(第二版)》中第十章的自定义委托例子,画星星的作法是一样的,都是通过 QApplication::style()->drawControl(QStyle::CE_CheckBox,&check_box_style_option,painter);这个函数,只不过选择的元素是QCheckBox的。

QTableView插入QCheckBox复选框_第1张图片

#ifndef CCHECKBOXMODEL_H
#define CCHECKBOXMODEL_H

#include 
#include 
#include 
#include 
#include 


class TableHeaderView :public QHeaderView
{
	Q_OBJECT
public:
	TableHeaderView(Qt::Orientation orientation, QWidget *parent);
	~TableHeaderView();

protected:
	void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
	bool event(QEvent *e) Q_DECL_OVERRIDE;
	void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
	void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;

	public slots:
	void onStateChanged(int state);

signals:
	void stateChanged(int state);

private:
	bool m_bPressed;
	bool m_bChecked;
	bool m_bTristate;
	bool m_bNoChange;
	bool m_bMoving;
};


class CheckBoxDelegate :public QStyledItemDelegate
{
	Q_OBJECT
public:
    CheckBoxDelegate(QObject *parent);
    ~CheckBoxDelegate();
    // painting
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

protected:
    bool editorEvent(QEvent *event, QAbstractItemModel *model,
                     const QStyleOptionViewItem &option, const QModelIndex &index);
};



#endif // TABLE_MODEL_H


#include "ccheckboxmodel.h"
#include 
#include 
#include 
#include 

#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif

#define CHECK_BOX_COLUMN 0
TableHeaderView::TableHeaderView(Qt::Orientation orientation, QWidget *parent)
	: QHeaderView(orientation, parent),
	m_bPressed(false),
	m_bChecked(false),
	m_bTristate(false),
	m_bNoChange(false),
	m_bMoving(false)
	
{	
    setSectionsClickable(true); // 响应鼠标
}

TableHeaderView::~TableHeaderView()
{

}

// 槽函数,用于更新复选框状态
void TableHeaderView::onStateChanged(int state)
{
	if (state == Qt::PartiallyChecked) {
		m_bTristate = true;
		m_bNoChange = true;
	}
	else {
		m_bNoChange = false;
	}

	m_bChecked = (state != Qt::Unchecked);
	update();
}

// 绘制复选框
void TableHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
	painter->save();
	QHeaderView::paintSection(painter, rect, logicalIndex);
	painter->restore();

	if (logicalIndex == CHECK_BOX_COLUMN)
	{
		QStyleOptionButton option;
		option.initFrom(this);

		if (m_bChecked)
			option.state |= QStyle::State_Sunken;

		if (m_bTristate && m_bNoChange)
			option.state |= QStyle::State_NoChange;
		else
			option.state |= m_bChecked ? QStyle::State_On : QStyle::State_Off;
		if (testAttribute(Qt::WA_Hover) && underMouse()) {
			if (m_bMoving)
				option.state |= QStyle::State_MouseOver;
			else
				option.state &= ~QStyle::State_MouseOver;
		}

		QCheckBox checkBox;
		option.iconSize = QSize(20, 20);
		option.rect = rect;
		style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, &checkBox);
	}
}

// 鼠标按下表头
void TableHeaderView::mousePressEvent(QMouseEvent *event)
{
	int nColumn = logicalIndexAt(event->pos());
	if ((event->buttons() & Qt::LeftButton) && (nColumn == CHECK_BOX_COLUMN))
	{
		m_bPressed = true;
	}
	else
	{
		QHeaderView::mousePressEvent(event);
	}
}

// 鼠标从表头释放,发送信号,更新model数据
void TableHeaderView::mouseReleaseEvent(QMouseEvent *event)
{

    if (m_bPressed)
    {
        if (m_bTristate && m_bNoChange)
        {
            m_bChecked = true;
            m_bNoChange = false;
        }
        else
        {
            m_bChecked = !m_bChecked;
        }

        update();

        Qt::CheckState state = m_bChecked ? Qt::Checked : Qt::Unchecked;

        emit stateChanged(state);

        updateSection(0);
    }
    else
    {
        QHeaderView::mouseReleaseEvent(event);
    }

    m_bPressed = false;
}

// 鼠标滑过、离开,更新复选框状态
bool TableHeaderView::event(QEvent *event)
{
	updateSection(0);
	if (event->type() == QEvent::Enter || event->type() == QEvent::Leave)
	{
		QMouseEvent *pEvent = static_cast<QMouseEvent *>(event);
		int nColumn = logicalIndexAt(pEvent->x());
		if (nColumn == CHECK_BOX_COLUMN)
		{
			m_bMoving = (event->type() == QEvent::Enter);

			update();
			return true;
		}
	}
	return QHeaderView::event(event);
}




CheckBoxDelegate::CheckBoxDelegate(QObject *parent) :QStyledItemDelegate(parent)
{

}

CheckBoxDelegate::~CheckBoxDelegate()
{

}

// 绘制复选框
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
	QStyleOptionViewItem viewOption(option);
	initStyleOption(&viewOption, index);
	if (option.state.testFlag(QStyle::State_HasFocus))
		viewOption.state = viewOption.state ^ QStyle::State_HasFocus;

	QStyledItemDelegate::paint(painter, viewOption, index);

	if (index.column() == CHECK_BOX_COLUMN)
	{
		bool data = index.model()->data(index, Qt::UserRole).toBool();

		QStyleOptionButton checkBoxStyle;
		checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;
		checkBoxStyle.state |= QStyle::State_Enabled;
		checkBoxStyle.iconSize = QSize(20, 20);
		checkBoxStyle.rect = option.rect;

		QCheckBox checkBox;
		checkBoxStyle.iconSize = QSize(20, 20);
		checkBoxStyle.rect = option.rect;
		QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &checkBox);

		checkBox.setEnabled(false);
	}
}

// 响应鼠标事件,更新数据
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
	QRect decorationRect = option.rect;

	QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
	if (event->type() == QEvent::MouseButtonPress && decorationRect.contains(mouseEvent->pos()))
	{
		if (index.column() == CHECK_BOX_COLUMN)
		{

				bool data = model->data(index, Qt::UserRole).toBool();
				model->setData(index, !data, Qt::UserRole);

		}
	}

	return QStyledItemDelegate::editorEvent(event, model, option, index);
}




#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 
#include "ccheckboxmodel.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;

private:
    TableHeaderView        *myHeader;
    QStandardItemModel     *model;
private:
    void iniVar();
    void iniUi();
    void iniConnect();
    void createItem(QStringList filename);
private slots:
    void headerStateChangedSlot(int state);
    void itemChangedSlot(QStandardItem* item);
};

#endif // WIDGET_H


#include "widget.h"
#include "ui_widget.h"
#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif

const QString headerStr = QObject::tr(" ,工况名");

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //--1 初始化
    iniVar();
    iniUi();
    iniConnect();

    //--2 创建表格项
    QStringList workingConditionName;
    workingConditionName<<tr("工况1")<<tr("工况2")<<tr("工况3");
    createItem(workingConditionName);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::iniVar()
{
    myHeader = new TableHeaderView(Qt::Horizontal, ui->tableView);
    model = new QStandardItemModel(ui->tableView);
}

void Widget::iniUi()
{
    ui->tableView->setHorizontalHeader(myHeader);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); //选中行
    QStringList headerList = headerStr.split(",");
    model->setHorizontalHeaderLabels(headerList);
    model->setColumnCount(headerList.size());
    CheckBoxDelegate *pCheckDelegate = new CheckBoxDelegate(this);
    ui->tableView->setItemDelegateForColumn(0, pCheckDelegate);
    ui->tableView->setModel(model);
}

void Widget::iniConnect()
{
    connect(myHeader, &TableHeaderView::stateChanged, this, &Widget::headerStateChangedSlot);
    connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(itemChangedSlot(QStandardItem*)));
}
void Widget::createItem(QStringList filename)
{
    int rowCount = filename.size();
    model->setRowCount(rowCount);
    for(int i = 0; i < rowCount; ++i)
    {
        model->setItem(i,1,new QStandardItem(filename.at(i)));
    }
}

void Widget::headerStateChangedSlot(int state)
{
    int rowCount = model->rowCount();
    if (state == 2)//全选
    {
        for (int j = 0; j<rowCount; j++)
        {
            QModelIndex index = model->index(j, 0, QModelIndex());
            model->setData(index, true, Qt::UserRole);
        }
    }
    else if (state == 0) //全不选
    {
        for (int j = 0; j<rowCount; j++)
        {
            QModelIndex index = model->index(j, 0, QModelIndex());
            model->setData(index, false, Qt::UserRole);
        }
    }

}

void Widget::itemChangedSlot(QStandardItem *item)
{
    int rowCount = model->rowCount();
    int column = item->index().column();
    if (column == 0)  //第0列  checkbox
    {
        Qt::CheckState state = Qt::Unchecked;
        int nSelectedCount = 0;
        for (int i = 0; i< rowCount; i++)
        {
            if (model->index(i, 0).data(Qt::UserRole).toBool())
            {
                nSelectedCount++;
            }
        }
        if (nSelectedCount >= rowCount)
        {
            state = Qt::Checked;
        }
        else if (nSelectedCount > 0)
        {
            state = Qt::PartiallyChecked;
        }
        myHeader->onStateChanged(state);
    }
}


你可能感兴趣的:(Qt,c++)