首页 > 代码库 > 第60课 自定义模型类(下)
第60课 自定义模型类(下)
1. 界面GUI设计
2. 界面的类图设计
3. 右键上下文菜单的实现
(1)定义菜单对象(QMenu)
(2)连接菜单中QAction对象到槽函数
(3)定义事件过滤器,并处理ContextMenu事件
(4)在当前鼠标的位置打开菜单对象
【编程实验】数据应用界面和右键菜单的实现
//main.cpp
#include "Widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
//Widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QTableView> #include <QPushButton> #include <QMenu> #include "ScoreInfoModel.h" class Widget : public QWidget { Q_OBJECT ScoreInfoModel m_model; QTableView m_view; QPushButton m_refreshBtn; QPushButton m_clearBtn; QPushButton m_scoreBtn; QMenu m_menu; protected slots: void onRefreshBtnClicked(); void onClearBtnClicked(); void onScoreBtnClicked(); void onDeleteActionClicked(); public: Widget(QWidget *parent = 0); bool eventFilter(QObject* obj, QEvent* evt); ~Widget(); }; #endif // WIDGET_H
//Widget.cpp
#include "Widget.h" #include "ScoreInfo.h" #include "ScoreInfoModel.h" #include "DataSource.h" #include <QMessageBox> #include <QEvent> #include <QDebug> Widget::Widget(QWidget *parent): QWidget(parent) { m_view.setParent(this); m_view.move(10,10); m_view.resize(345, 180); m_view.installEventFilter(this); m_refreshBtn.setParent(this); m_refreshBtn.move(10,200); m_refreshBtn.resize(95, 30); m_refreshBtn.setText("Refresh"); m_clearBtn.setParent(this); m_clearBtn.move(135,200); m_clearBtn.resize(95, 30); m_clearBtn.setText("Clear"); m_scoreBtn.setParent(this); m_scoreBtn.move(260,200); m_scoreBtn.resize(95, 30); m_scoreBtn.setText("Score"); m_menu.addAction("Delete"); m_model.setView(m_view); connect(&m_refreshBtn, SIGNAL(clicked()), this, SLOT(onRefreshBtnClicked())); connect(&m_clearBtn, SIGNAL(clicked()), this, SLOT(onClearBtnClicked())); connect(&m_scoreBtn, SIGNAL(clicked()), this, SLOT(onScoreBtnClicked())); connect(m_menu.actions()[0], SIGNAL(triggered()), this, SLOT(onDeleteActionClicked())); onRefreshBtnClicked(); } void Widget::onRefreshBtnClicked() { DataSource ds; m_model.clear(); if(ds.setDataPath("C:/Users/SantaClaus/Desktop/test.txt")) { m_model.add(ds.fetchData()); } else { QMessageBox::critical(this, "Error", "Data source read error!", QMessageBox::Ok); } } void Widget::onClearBtnClicked() { m_model.clear(); } void Widget::onScoreBtnClicked() { int min = 256; int max = 0; int average = 0; if(m_model.count() > 0) { for(int i=0; i<m_model.count(); i++) { ScoreInfo info = m_model.getItem(i); if(info.score() < min) { min = info.score(); } if(info.score() > max) { max = info.score(); } average += info.score(); } average /= m_model.count(); QMessageBox::information(this, "Statistic", QString().sprintf("Min: %d\nMax: %d\nAverage: %d",min, max, average), QMessageBox::Ok); } else { QMessageBox::information(this, "Statistic", "No data record!", QMessageBox::Ok); } } bool Widget::eventFilter(QObject* obj, QEvent* evt) { if((obj == &m_view) && (evt->type() == QEvent::ContextMenu)) { m_menu.exec(QCursor::pos()); } return QWidget::eventFilter(obj, evt); } void Widget::onDeleteActionClicked() { m_model.remove(m_view.currentIndex().row()); } Widget::~Widget() { }
//ScoreInfo.h
#ifndef SCOREINFO_H #define SCOREINFO_H #include <QObject> class ScoreInfo : public QObject { Q_OBJECT QString m_id; QString m_name; int m_score; public: explicit ScoreInfo(QObject *parent = 0); explicit ScoreInfo(QString id, QString name, int score, QObject *parent = 0); //重写复制构造函数和赋值操作符,以便对三个成员变量进行赋值操作 ScoreInfo(const ScoreInfo& obj); ScoreInfo& operator=(const ScoreInfo& obj); QString id(); QString name(); int score(); }; #endif // SCOREINFO_H
//ScoreInfo.cpp
#include "ScoreInfo.h" ScoreInfo::ScoreInfo(QObject *parent) : QObject(parent) { m_id = "NULL"; m_name = "NULL"; m_score = -1; } ScoreInfo::ScoreInfo(QString id, QString name, int score, QObject *parent) : QObject(parent) { m_id = id; m_name = name; m_score = score; } ScoreInfo::ScoreInfo(const ScoreInfo& obj):QObject() //不能QObject(obj.parent()) { m_id = obj.m_id; m_name = obj.m_name; m_score = obj.m_score; } ScoreInfo& ScoreInfo::operator=(const ScoreInfo& obj) { if(this != &obj) { //不能setParent(obj.parent()),因为当: //ScoreInfo info; //info = ScoreInfo(...);时会把临时对象的parent传给obj m_id = obj.m_id; m_name = obj.m_name; m_score = obj.m_score; } return *this; } QString ScoreInfo::id() { return m_id; } QString ScoreInfo::name() { return m_name; } int ScoreInfo::score() { return m_score; }
//DataSource.h
#ifndef DATASOURCE_H #define DATASOURCE_H #include <QObject> #include <QList> #include "ScoreInfo.h" class DataSource : public QObject { Q_OBJECT QList<ScoreInfo> m_data; //这里是个小技巧,通过返回值来判断info里保存的数据是否有效 bool parse(QString line, ScoreInfo& info); public: explicit DataSource(QObject* parent = 0); bool setDataPath(QString path); QList<ScoreInfo> fetchData(); int count(); }; #endif // DATASOURCE_H
//DataSource.cpp
#include "DataSource.h" #include <QFile> #include <QTextStream> #include <QStringList> DataSource::DataSource(QObject* parent): QObject(parent) { } bool DataSource::parse(QString line, ScoreInfo& info) { bool ret = false; QStringList list = line.split("," , QString::SkipEmptyParts); if(list.count() == 3) { QString id = list[0].trimmed(); QString name = list[1].trimmed(); QString score = list[2].trimmed(); int value = http://www.mamicode.com/score.toInt(&ret); if(ret && (0 <= value ) && (value <= 150)) { info = ScoreInfo(id, name, value); } else { ret = false; } } return ret; } bool DataSource::setDataPath(QString path) { bool ret = false; QFile file(path); if( file.open(QIODevice::ReadOnly | QIODevice::Text) ) { QTextStream in(&file); while( !in.atEnd()) { ScoreInfo info; if( parse(in.readLine(),info)) { m_data.append(info); } } file.close(); ret = true; } return ret; } //为什么是fetchData而不是getData? QList<ScoreInfo> DataSource::fetchData() { QList<ScoreInfo> ret = m_data; m_data.clear(); //清空原来的数据,可以腾出空间以便下次获取数据 //如果getData这里就不应被清空,这也将导致m_data里 //的数据不断增加 return ret; } int DataSource::count() { return m_data.count(); }
//ScoreInfoModel.h
#ifndef SCOREINFOMODEL_H #define SCOREINFOMODEL_H #include <QObject> #include <QStandardItem> #include <QTableView> #include <QList> #include "ScoreInfo.h" class ScoreInfoModel : public QObject { Q_OBJECT QStandardItemModel m_model; void initHorizonHeaderLabels(); public: explicit ScoreInfoModel(QObject *parent = 0); bool add(ScoreInfo info); bool add(QList<ScoreInfo> list); bool remove(int index); ScoreInfo getItem(int index); int count(); void clear(); void setView(QTableView& view); }; #endif // SCOREINFOMODEL_H
//ScoreInfoModel.cpp
#include "ScoreInfoModel.h" ScoreInfoModel::ScoreInfoModel(QObject *parent) : QObject(parent) { initHorizonHeaderLabels(); } void ScoreInfoModel::initHorizonHeaderLabels() { QStringList list; list.append("ID"); list.append("Name"); list.append("Score"); m_model.setHorizontalHeaderLabels(list); } bool ScoreInfoModel::add(ScoreInfo info) { QStandardItem* root = m_model.invisibleRootItem(); QStandardItem* item0 = new QStandardItem(); //编号 QStandardItem* item1 = new QStandardItem(); //姓名 QStandardItem* item2 = new QStandardItem(); //成绩 bool ret = false; if(m_model.rowCount() > 0) initHorizonHeaderLabels(); if((root != NULL) && (item0 != NULL ) && (item1 != NULL) && (item2 != NULL)) { item0->setData(info.id(), Qt::DisplayRole); item1->setData(info.name(), Qt::DisplayRole); item2->setData(info.score(), Qt::DisplayRole); item0->setEditable(false); item1->setEditable(false); item2->setEditable(false); int newRow = count(); root->setChild(newRow, 0, item0); root->setChild(newRow, 1, item1); root->setChild(newRow, 2, item2); ret = true; } return ret; } bool ScoreInfoModel::add(QList<ScoreInfo> list) { bool ret = true; for(int i=0; i<list.count(); i++) { ret = ret && add(list[i]); } return ret; } bool ScoreInfoModel::remove(int index) { bool ret = false; if( (0 <= index) && (index <count())) { m_model.removeRow(index); ret = true; } return ret; } ScoreInfo ScoreInfoModel::getItem(int index) { ScoreInfo ret; if( (0 <= index) && (index <count())) { QModelIndex idx0 = m_model.index(index, 0, QModelIndex()); QModelIndex idx1 = m_model.index(index, 1, QModelIndex()); QModelIndex idx2 = m_model.index(index, 2, QModelIndex()); QVariant v0 = idx0.data(Qt::DisplayRole); QVariant v1 = idx1.data(Qt::DisplayRole); QVariant v2 = idx2.data(Qt::DisplayRole); ret = ScoreInfo(v0.toString(), v1.toString(), v2.toInt()); } return ret; } int ScoreInfoModel::count() { return m_model.rowCount(); } void ScoreInfoModel::clear() { m_model.clear(); } void ScoreInfoModel::setView(QTableView& view) { view.setModel(&m_model); }
4. 小结
(1)数据源类(DataSource)用于抽象表示数据的来源
(2)模型类(Model)用于从数据源获取数据并组织
(3)视图类(View)用于显示模型中的数据
(4)数据应用4层架构设计非常易于扩展和维护
第60课 自定义模型类(下)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。