QT_MVC使用例子

5 篇文章 0 订阅

TableModel.h

#pragma once

#include <QObject>
#include <QAbstractItemModel>

struct FlashIndexData{
	FlashIndexData() :is_be_checked(false){
	}
	bool is_be_checked;
	quint32 unix_time;
	quint16 addr;
};

class TableModel : public QAbstractItemModel
{
	Q_OBJECT

public:
	TableModel(QObject *parent = nullptr);
	~TableModel();

	//需要实现的5个函数
	virtual int rowCount(const QModelIndex & parent = QModelIndex()) const;
	virtual int columnCount(const QModelIndex & parent = QModelIndex()) const;
	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
	virtual QModelIndex index(int row, int column,
		const QModelIndex &parent = QModelIndex()) const;//返回每个数据项的index
	virtual QModelIndex parent(const QModelIndex &index) const;//本需求树只有一层,parent返回NULL

	//剩余根据需求
	virtual bool setData(const QModelIndex & index, const QVariant & value, 
		int role = Qt::EditRole);//设置数据
	virtual Qt::ItemFlags flags(const QModelIndex & index) const;//返回Item项的可选,可用户点击等标识

	virtual QVariant headerData(int section, Qt::Orientation orientation, 
		int role = Qt::DisplayRole) const;//返回相应role的表头数据

	void setFlashData(QList<FlashIndexData> &flash_data);
	void clear();
	void getSelectedFlashData(QList<int>& listRow);
	public slots:
	void slot_stateChanged(Qt::CheckState state);

	void deleteData();

private:
	QList<FlashIndexData> m_flash_index;    //flash 索引
	
	void onStateChanged();
	enum{
		CHECK_BOX_COLUMN = 0,
		UNIX_TIME_COLUMN,
		FLASH_ADDR_COLUMN
	};

signals:
	void stateChanged(Qt::CheckState state);
};

TableModel.cpp

#include "TableModel.h"
#include <QDateTime>
#include <QColor>
#include <QSize>
#include <QFont>
#include <QBrush>

TableModel::TableModel(QObject *parent)
	: QAbstractItemModel(parent)
{
	m_flash_index.clear();
}

TableModel::~TableModel()
{
}
int TableModel::rowCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);

	return m_flash_index.count();
}
int TableModel::columnCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);

	return 3;
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();
	int row = index.row();
	int column = index.column();
	FlashIndexData index_data = m_flash_index.at(row);

	switch (role) {
	case Qt::DisplayRole:
		if (column == UNIX_TIME_COLUMN)
			return index_data.unix_time;/*QDateTime::fromTime_t(index_data.unix_time).toString("yyyy-MM-dd hh:mm:ss");*/
		else if (column == FLASH_ADDR_COLUMN)
			return index_data.addr;
		return "";
		break;
	case Qt::CheckStateRole:
		if (column == CHECK_BOX_COLUMN)
			return index_data.is_be_checked ? Qt::Checked : Qt::Unchecked;
		break;
	case Qt::TextAlignmentRole:
		if (column == CHECK_BOX_COLUMN)
			return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
		else
			return Qt::AlignCenter;
		break;
	case Qt::TextColorRole:
		return QColor(Qt::black);
		break;
	case Qt::SizeHintRole:
		return QSize(100, 30);
		break;
	case Qt::FontRole:
		return QFont("SimSun", 11);
		break;
	default:
		break;
	}
	return QVariant();
}

//可编辑,只提供可选不可选的编辑,不提供对数据源的编辑
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
	if (!index.isValid())
		return false;
	int column = index.column();
	FlashIndexData index_data = m_flash_index.at(index.row());
	switch (role) {
	case Qt::UserRole:  //根据表头的复选框选择
	case Qt::CheckStateRole:   //根据鼠标点击
		if (column == CHECK_BOX_COLUMN)
		{
			index_data.is_be_checked = (((Qt::CheckState)value.toInt()) == Qt::Checked);
			m_flash_index.replace(index.row(), index_data);

			emit dataChanged(index, index);

			if (role == Qt::CheckStateRole)  //点击鼠标,更新表头复选框状态
				onStateChanged();

			return true;
		}
		break;
	default:
		return false;
		break;
	}
	return false;
}
QModelIndex TableModel::index(int row, int column, const QModelIndex &parent) const
{
	if (row < 0 || column < 0 || column >= columnCount(parent))
		return QModelIndex();

	return createIndex(row, column);
}
QModelIndex TableModel::parent(const QModelIndex &index) const
{
	Q_UNUSED(index);
	return QModelIndex();
}

QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	switch (role) {
	case Qt::DisplayRole:
		if (section == CHECK_BOX_COLUMN)
		{
			return QString::fromLocal8Bit("全选");
		}
		else if (section == UNIX_TIME_COLUMN)
		{
			return QString::fromLocal8Bit("时间");
		}
		else if (section == FLASH_ADDR_COLUMN)
		{
			return QString::fromLocal8Bit("地址");
		}
		return "";
		break;
	case Qt::FontRole:
		return QFont("SimSun", 12);
		break;
	case Qt::TextAlignmentRole:
		return Qt::AlignCenter;
		break;
	case Qt::TextColorRole:
		return QColor(Qt::black);
		break;
	case Qt::SizeHintRole:
		return QSize(100, 40);
		break;
	case Qt::BackgroundRole:
		return QBrush(Qt::black);
		break;
	default:
		break;
	}
	return QVariant();
}

//可选
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
	{
		return QAbstractItemModel::flags(index);
	}
		

	Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable 
		| Qt::ItemNeverHasChildren;

	if (index.column() == CHECK_BOX_COLUMN)
		flags |= Qt::ItemIsUserCheckable;
	return flags;
}


void TableModel::setFlashData(QList<FlashIndexData> &flash_data)
{
	m_flash_index = flash_data;

	beginResetModel();
	endResetModel();

	emit stateChanged(Qt::Unchecked);
}

void TableModel::clear()
{
	m_flash_index.clear();
	beginResetModel();
	endResetModel();

	emit stateChanged(Qt::Unchecked);
}

void TableModel::getSelectedFlashData(QList<int>& listRow)
{
	listRow.clear();
	for (int i = 0; i < rowCount(); ++i)
	{
		if (m_flash_index.at(i).is_be_checked)
		{
			listRow.append(i);
			//selected_list.insert(m_flash_index.at(i).unix_time, m_flash_index.at(i).addr);
		}
	}
}

void TableModel::deleteData()
{
	for (int i = 0; i < rowCount(); ++i)
	{
		if (m_flash_index.at(i).is_be_checked)
		{
			m_flash_index.removeAt(i);
		}
	}

	beginResetModel();
	endResetModel();

	emit stateChanged(Qt::Unchecked);
}

void TableModel::onStateChanged()
{
	int select_total = 0;
	for (int i = 0; i < rowCount(); ++i)
	{
		if (m_flash_index.at(i).is_be_checked)
			++select_total;
	}

	if (select_total == 0)
	{
		emit stateChanged(Qt::Unchecked);
	}
	else if (select_total < rowCount())
	{
		emit stateChanged(Qt::PartiallyChecked);
	}
	else
	{
		emit stateChanged(Qt::Checked);
	}
}

void TableModel::slot_stateChanged(Qt::CheckState state)
{
	for (int i = 0; i < rowCount();i++)
	{
		setData(index(i, CHECK_BOX_COLUMN), state, Qt::UserRole);
	}
}

HeaderView.h

#pragma once

#include <QObject>
#include <QHeaderView>

class HeaderView : public QHeaderView
{
	Q_OBJECT

public:
	HeaderView(QWidget *parent);
	~HeaderView();

protected:
	virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
	virtual void mousePressEvent(QMouseEvent *e);
	virtual void mouseReleaseEvent(QMouseEvent *e);
signals:
	void stateChanged(Qt::CheckState state);
	private slots:
	void slot_stateChanged(Qt::CheckState state);
private:
	Qt::CheckState m_state;
	bool m_is_pressed;
};

HeaderView.cpp

#include "HeaderView.h"
#include <QPainter>
#include <QMouseEvent>

//默认水平表头
HeaderView::HeaderView(QWidget *parent)
	: QHeaderView(Qt::Horizontal, parent)
{
	m_state = Qt::Unchecked;
	m_is_pressed = false;
	setSectionsClickable(true);
}
 
HeaderView::~HeaderView()
{
}
void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
	painter->save();
	QHeaderView::paintSection(painter, rect, logicalIndex);//绘制其他Section
	painter->restore();

	//绘制背景色
	painter->save();
	painter->setBrush(QBrush(Qt::gray));
	painter->setPen(Qt::NoPen);
	painter->drawRect(rect);
	//绘制Section的Text
	painter->setFont(QFont("SimSun", 12));
	painter->setPen(QColor("#000000"));
	painter->drawText(rect, Qt::AlignCenter, model()->headerData(logicalIndex, Qt::Horizontal).toString());
	painter->restore();
	//为第一列绘制Checkbox
	if (logicalIndex == 0)
	{
		QStyleOptionButton option;
		option.initFrom(this);
		if (m_state == Qt::Unchecked)
		{
			option.state |= QStyle::State_Off;
		}
		else if (m_state == Qt::PartiallyChecked)
		{
			option.state |= QStyle::State_NoChange;
		}
		else if (m_state == Qt::Checked)
		{
			option.state |= QStyle::State_On;
		}
		option.iconSize = QSize(20, 20);
		option.rect = QRect(QPoint(rect.left() + 5, rect.top() + (rect.height() - 20) / 2), QPoint(rect.left() + 25, rect.bottom() - (rect.height() - 20) / 2));
		style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
	}
}

void HeaderView::mousePressEvent(QMouseEvent *e)
{
	int nColumn = logicalIndexAt(e->pos());
	if ((e->buttons() & Qt::LeftButton) && (nColumn == 0))
	{
		m_is_pressed = true;

		e->accept();
	}
	e->ignore();
}

void HeaderView::mouseReleaseEvent(QMouseEvent *e)
{
	if (m_is_pressed)
	{
		if (m_state == Qt::Unchecked)
		{
			m_state = Qt::Checked;
		}
		else
		{
			m_state = Qt::Unchecked;
		}
		updateSection(0);
		emit stateChanged(m_state); //状态改变
	}
	m_is_pressed = false;
	e->accept();
}
//根据Item的复选框状态,表头复选框状态更新
void HeaderView::slot_stateChanged(Qt::CheckState state)
{
	m_state = state;
	updateSection(0);
}

MVCDemo.h

#pragma once


#include <QtWidgets/QMainWindow>
#include "ui_MVCDemo.h"
#include "TableModel.h"
#include "HeaderView.h"

class MVCDemo : public QMainWindow
{
	Q_OBJECT

public:
	MVCDemo(QWidget *parent = Q_NULLPTR);

public slots:
	void slot_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);

	void on_pushButton_clicked();
	void on_pushButtonAdd_clicked();
	void on_pushButtonDelete_clicked();

private:
	Ui::MVCDemoClass ui;
	TableModel* m_pMode = nullptr;
	HeaderView* m_pHeaderView = nullptr;
	QList<FlashIndexData> m_listData;


};

MVCDemo.cpp

#include "MVCDemo.h"
#include <QDateTime>


MVCDemo::MVCDemo(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	m_pMode = new TableModel(this);
	m_pHeaderView = new HeaderView(this);
	ui.tableView->setModel(m_pMode);
	ui.tableView->setHorizontalHeader(m_pHeaderView);

	
	for (int i = 0; i < 20;i++)
	{
		FlashIndexData stuData;
		stuData.is_be_checked = false;
		stuData.unix_time = 1111 + i;
		stuData.addr = 22 + i;
		m_listData.append(stuData);
	}

	m_pMode->setFlashData(m_listData);

	ui.tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
	ui.tableView->setColumnWidth(0, 150);
	ui.tableView->setColumnWidth(1, 400);
	ui.tableView->horizontalHeader()->setStretchLastSection(true);
	ui.tableView->verticalHeader()->hide();

	connect(m_pHeaderView, SIGNAL(stateChanged(Qt::CheckState)), m_pMode, SLOT(slot_stateChanged(Qt::CheckState)));
	connect(m_pMode, SIGNAL(stateChanged(Qt::CheckState)), m_pHeaderView, SLOT(slot_stateChanged(Qt::CheckState)));
	connect(ui.tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(slot_selectionChanged(QItemSelection, QItemSelection)));
}

void MVCDemo::slot_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
	for (int i = 0; i < selected.indexes().count(); ++i)
	{
		m_pMode->setData(selected.indexes().at(i), Qt::Checked, Qt::UserRole + 1);
	}

	for (int i = 0; i < deselected.indexes().count(); ++i)
	{
		m_pMode->setData(deselected.indexes().at(i), Qt::Unchecked, Qt::UserRole + 1);
	}
}

void MVCDemo::on_pushButton_clicked()
{
	QList<int> listRow;
	m_pMode->getSelectedFlashData(listRow);
	for (auto r:listRow)
	{
		ui.tableView->setRowHidden(r, true);
	}
}
void MVCDemo::on_pushButtonAdd_clicked()
{
	FlashIndexData stuData;
	stuData.is_be_checked = true;
	stuData.unix_time = 4000;
	stuData.addr = 8000;
	m_listData.append(stuData);
	m_pMode->setFlashData(m_listData);
}
void MVCDemo::on_pushButtonDelete_clicked()
{
	//QList<int> listRow;
	//m_pMode->getSelectedFlashData(listRow);
	m_pMode->deleteData();
}

main.cpp

#include "MVCDemo.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	MVCDemo w;
	w.show();
	return a.exec();
}

 

Qt是一个跨平台的应用程序开发框架,提供了一套用于构建图形界面和处理逻辑的工具和库。MVC(Model-View-Controller)则是一种设计模式,用于将应用程序的数据、界面和逻辑进行分离,以便于管理和维护。 下面是一个使用QtMVC框架的例子: 假设我们正在开发一个简单的联系人管理程序,其中需要显示联系人列表并支持添加、删除和编辑联系人的功能。 首先,我们定义一个Contact类来表示联系人的数据模型。这个类可以包含联系人的姓名、电话号码、电子邮箱等信息。 接下来,我们创建一个继承自QAbstractTableModel的ContactTableModel类,负责提供联系人模型的数据和视图的交互。在这个类中,我们需要实现一些必要的函数,比如rowCount()、columnCount()、data()等,来返回联系人模型的行数、列数和具体数据。 然后,我们创建一个继承自QTableView的ContactTableView类,用于显示联系人列表。在这个类中,我们需要将ContactTableModel设置为其模型,并添加一些额外的功能,比如双击联系人时弹出详细信息编辑框等。 最后,我们创建一个继承自QDialog的ContactEditDialog类,用于编辑联系人的详细信息。在这个类中,我们可以添加各种输入框和按钮,然后在用户完成编辑后,将更新后的数据保存到ContactTableModel中。 通过以上的类的设计,我们可以将联系人的数据、视图和逻辑进行分离,方便我们对这些部分进行独立管理和扩展。比如,如果需要从数据库中读取联系人数据,我们只需要修改ContactTableModel类的data()函数,而不需要更改其他部分的代码。 总的来说,QtMVC框架提供了一种结构化的方式来开发和管理复杂的应用程序,它能够提高代码的可维护性和可扩展性。以上例子只是一个简单的示例,实际应用中可能涉及更多的功能和类的设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值