Qt+mysql搭建系统---转载的
1. 搭建系统前面介绍了利用python+vue搭建全栈系统:移动端篇:H5+搭建移动端应用前端篇:Vue2.0搭建PC前端后台篇:Flask搭建系统后台项目线上地址:项目访问链接,账号:admin 密码:admin本文讲介绍另外一种技术,利用Qt框架搭建一个小型系统。系统有以下特点:系统是异步处理,mysql操作在线程里,操作完后数据通过信号槽发送到页面展示查询mysql百万数量级数据表,用QT
1. 搭建系统
前面介绍了利用python+vue搭建全栈系统:
移动端篇:H5+搭建移动端应用
前端篇:Vue2.0搭建PC前端
后台篇:Flask搭建系统后台
项目线上地址:项目访问链接,账号:admin 密码:admin
本文讲介绍另外一种技术,利用Qt框架搭建一个小型系统。系统有以下特点:
系统是异步处理,mysql操作在线程里,操作完后数据通过信号槽发送到页面展示
查询mysql百万数量级数据表,用QTableView+自定义数据模型轻松展示
QTableView加载自定义模型,展示百万条数据消耗比较少的内存(600MB左右内存,用Qt自带的QStandardItemModel模型消耗2635MB内存)
页面里面控件会随窗口自动缩放
1.1. 技术栈如下:
开发语言:C++
数据库:MySQL5.7
开发框架:Qt5.12
开发工具:Qt Creator 4.9.0 (Enterprise)
其他工具1:XAPP(集成apach和mysql)
其他工具2:Navicat 11.0.10
1.2. 系统的详细开发过程
1.2.1. 用Qt Creator 4.9.0创建项目
项目创建完成后运行如下图:
项目创建完成后运行如下图:
1.2.2. 创建资源文件
由于项目中需要用到图片,我们创建一个资源文件resource.qrc,如图
把图片添加到resource.qrc里面,
1.2.3. 添加项目需要的模块
由于系统里面需要访问mysql数据库,并需要显示图表,所以在工程文件pro里面需要添加模块。创建好项目后自带模块,如图:
添加数据库和图表模块,如图:
1.2.4. 创建项目文件和目录
项目目录结构如上图,文件和目录的说明如下:
C3DModels:Qt界面设计类,继承CBaseWidget类,展示3D模型
CBaseWidget:Qt类,作为其他页面的基类,实现页面缩放、页面进度条功能
CDataclass:Qt类,数据异步处理类,由页面触发,处理完成后通过信号发送处理结果给页面
CHome:Qt界面设计类,继承CBaseWidget类,登录成功后跳转到的主页面,展示功能页面
CLogin:Qt界面设计类,继承CBaseWidget类,登录页面
CLogs:Qt界面设计类,继承CBaseWidget类,日志页面
Common:Qt类,单例类,注册元类型和初始化mysql数据库
CQCharts:Qt界面设计类,继承CBaseWidget类,展示Qt画图页面
CUsers:Qt界面设计类,继承CBaseWidget类,用户页面,用QTableView展示百万数量及表格
CWorker:Qt类,在线程中运行,主要查询mysql
main.cpp:项目入口文件
下面我们来创建上面的列表类文件
1.2.4.1. 创建Common类
Common类是一个单例类,有以下功能:
负责初始化数据库
获取数据库实例
定义控件缩放函数
定义系统常量和数据结构
//定义组件缩放的基准
#define STD_WIDTH 1920 //组件缩放的基准宽度
#define STD_HIGHT 1080 //组件缩放的基准高度
//定义数据处理结果状态码
enum RET_CODE {
RET_OK = 0, //成功
RET_DBERR_OPEN, //数据库查询打开失败
RET_DBERR_RUN, //SQL执行失败
RET_PARAMERR, //参数错误
RET_NOFUNC, //方法不存在
RET_NOWORKTYPE //处理类型不存在
};
//定义数据处理结果状态码对应的信息
extern QStringList RET_MSG;
//定义命令参数数据结构
typedef struct _CmdData {
QString func; //处理的函数名称
QMap<QString, QString> params; //参数列表
} CmdData;
//定义命令处理结果数据结构
typedef struct _RstData {
int retCode; //结果状态码
QString func; //处理的函数名称
QString msg; //结果信息
QVector< QVector<QString> > result; //处理结果数据,二位数组
} RstData;
// MYSQL数据库信息
typedef struct _MysqlInfo
{
int port;
QString host, name, usr, pwd;
} MysqlInfo;
class MyCommon : public QWidget
{
Q_OBJECT
public:
explicit MyCommon(QWidget *parent = nullptr);
~MyCommon();
static MyCommon *instance(); //定义单例类
static void InitDataBase(const MysqlInfo &dbInfo); //初始化数据库
static void scalWidget(QWidget *widget, float xc = 1, float yc = 1); //缩放组件函数
static QSqlDatabase GetNewDatabase() //获取数据库实例
{
QSqlDatabase newDb;
if (QSqlDatabase::contains("mysql_1"))
{
int n = QSqlDatabase::connectionNames().size();
newDb = QSqlDatabase::cloneDatabase(mDatabase, QString("mysql_%1").arg(n));
}
else
{
newDb = QSqlDatabase::cloneDatabase(mDatabase, "mysql_1");
}
return newDb;
}
signals:
public slots:
private:
static float xScal, yScal;
static QRect mScreenRect;
static MyCommon *self;//单例模式
static QSqlDatabase mDatabase;
static MysqlInfo mDbInfo;
};
1.2.4.2. 创建CDataClass类
CDataClass是Qt类,有以下功能:
- 定义多线程,把数据处理移到线程里面处理
- 定义命令处理函数,供页面调用
- 定义发送命令信号,把从页面接受的命令发送到线程里面
- 定义接收处理结果槽函数
- 定义发送处理结果信号,把从数据返回到页面
class CDataClass;
typedef void (CDataClass::*PTRFUN)(const CmdData &argcs); //函数指针,用于分发命令
class CDataClass : public QObject
{
Q_OBJECT
public:
explicit CDataClass(QObject *parent = nullptr);
~CDataClass()
{
mWorkerThread.quit();
mWorkerThread.wait();
}
QVariant testGetData(int count); //测试函数
void handleCmdData(const CmdData &argcs); //供页面调用的命令函数,分发到具体的处理函数
void checkUserPwd(const CmdData &argcs); //验证输入的用户名和密码
void getUsersData(const CmdData &argcs); //查询用户信息
void addUsersData(const CmdData &argcs); //增加用户信息
void editUsersData(const CmdData &argcs); //编辑用户信息
void getLogsData(const CmdData &argcs); //查询日志信息
signals:
//把页面接受的命令,发送到线程里面的槽函数
void operate(const int type, const QString &func, const QString &cmd);
//把线程里面的处理结果返回给页面
void operateResult(const RstData &rstData);
public slots:
void handleResults(const RstData &rstData); //接受线程里面处理结果
private:
QThread mWorkerThread; //定义处理线程
QMap<QString, PTRFUN> mFuncMap; //定义命令处理函数映射关系
};
构造函数初始化
CDataClass::CDataClass(QObject *parent) : QObject(parent)
{
Worker *worker = new Worker; //定义数据处理类
worker->moveToThread(&mWorkerThread); //把数据处理类移到线程
connect(&mWorkerThread, &QThread::finished, worker, &QObject::deleteLater);
//定义信号槽,把命令发送到线程里面的槽函数
connect(this, &CDataClass::operate, worker, &Worker::doWork);
//定义信号槽,接收线程里面发送的结果
connect(worker, &Worker::resultReady, this, &CDataClass::handleResults);
mWorkerThread.start(); //开启线程
//初始化命令处理函数映射关系
mFuncMap["checkUserPwd"] = &CDataClass::checkUserPwd;
mFuncMap["getUsersData"] = &CDataClass::getUsersData;
mFuncMap["addUsersData"] = &CDataClass::addUsersData;
mFuncMap["editUsersData"] = &CDataClass::editUsersData;
mFuncMap["getLogsData"] = &CDataClass::getLogsData;
}
1.2.4.3. 创建CWorker类
CWorker是Qt类,有以下功能:
- 定义mysql操作函数
- 定义接收页面命令槽函数
- 定义发送处理结果信号,把从数据返回到页面
//定义线程里面支持的处理数据的操作
enum WORK_TYPE {
WORK_DB_QUERY = 0, //数据库查询
WORK_DB_RUN //数据库更新(增、删、改)
};
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
void testAddData1(); //测试函数
signals:
void resultReady(const RstData &rstData); //返回处理结果信号
public slots:
void doWork(const int type, const QString &func, const QString &cmd); //接收页面命令槽函数
private:
QSqlDatabase mDatabase; //数据库操作对象
int RunSql(const QString &sqlStr); //执行sql语句,写入接口
int RunSql(const QString &prepare, const QMap<QString, QVariant> &values);
int RunSqlColRow(const QString &sqlStr, QVector< QVector<QString> > &result); //执行sql语句,查询接口, 返回二维数组[列][行]
int RunSqlRowCol(const QString &sqlStr, QVector< QVector<QString> > &result); //执行sql语句,查询接口, 返回二维数组[行][列]
};
1.2.4.4. 创建CBaseWidget类
CBaseWidget是Qt类,作为其他页面的基类,有以下功能:
- 作为其他页面的基类
- 实现组件随页面缩放
- 定义CDataClass对象,发送命令和接收处理结果
class CBaseWidget : public QWidget
{
Q_OBJECT
public:
explicit CBaseWidget(QWidget *parent = nullptr);
~CBaseWidget();
void initWidgets(QWidget *pageWidget, bool scaleFlag = true);
void resizeWidget();
void resizeEvent(QResizeEvent *event);
void handleCmdData(const CmdData &argcs);
void handleCmdDataList(const QVector<CmdData> &argcsList);
signals:
void operateResult(const RstData &rstData);
public slots:
void handleResults(const RstData &rstData);
private:
QMap<QString, QRect> mWidRectMap;
CDataClass *mHandle;
DialogProcessBar *mDlgProcess;
bool mScaleFlag;
QVector<CmdData> mArgcsVec;
};
1.2.4.5. 创建CLogin类
CBaseWidget是Qt界面设计类,继承CBaseWidget类,有以下功能:
- 用户登录页面
namespace Ui { class CLoginForm; } class CLoginForm : public CBaseWidget { Q_OBJECT public: explicit CLoginForm(CBaseWidget *parent = nullptr); ~CLoginForm(); private slots: void handleMainWidExit(); //退出登录槽函数 void on_pbtLogin_clicked(); //登录槽函数 void handleResults(const RstData &rstData); //接收线程处理结果槽函数 private: Ui::CLoginForm *ui; CHomeForm *mMainWid; //定义主窗口 };
1.2.4.6. 创建CHome类
CHome是Qt界面设计类,继承CBaseWidget类,有以下功能:
- 显示菜单导航栏
- 根据菜单显示不同页面
- 退出登录
namespace Ui { class CHomeForm; } class CHomeForm : public CBaseWidget { Q_OBJECT public: explicit CHomeForm(CBaseWidget *parent = nullptr); ~CHomeForm(); void initMenu(); signals: void signalExit(); private slots: void on_pbtChangePwd_clicked(); void on_pushExit_clicked(); void handleResults(const RstData &rstData); void handleMenuClicked(const QModelIndex &index); void handleTimerUpdate(); private: Ui::CHomeForm *ui; QTimer *mTimerUpdate; QStringList mMenuData1; QVector<QStringList> mMenuData2; C3DModelsForm *m3DModels; CQChartsForm *mCharts; CUsersForm *mUsers; CLogsForm *mLogs; };
构造函数初始化,初始化展示页面对象指针,析构时删除页面对象指针
CHomeForm::CHomeForm(CBaseWidget *parent) : CBaseWidget(parent), ui(new Ui::CHomeForm) { ui->setupUi(this); m3DModels = new C3DModelsForm(); m3DModels->setParent(this->ui->frameContent); m3DModels->hide(); mCharts = new CQChartsForm(); mCharts->setParent(this->ui->frameContent); mCharts->hide(); mUsers = new CUsersForm(); mUsers->setParent(this->ui->frameContent); mUsers->hide(); mLogs = new CLogsForm(); mLogs->setParent(this->ui->frameContent); mLogs->hide(); this->initWidgets(this); initMenu(); mTimerUpdate = new QTimer(this); connect(mTimerUpdate, &QTimer::timeout, this, &CHomeForm::handleTimerUpdate); mTimerUpdate->start(1000); handleTimerUpdate(); connect(this, &CHomeForm::operateResult, this, &CHomeForm::handleResults); } CHomeForm::~CHomeForm() { delete ui; if (mTimerUpdate != nullptr) { delete mTimerUpdate; } if (m3DModels != nullptr) { delete m3DModels; } if (mCharts != nullptr) { delete mCharts; } if (mUsers != nullptr) { delete mUsers; } if (mLogs != nullptr) { delete mLogs; } }
初始化菜单导航栏
void CHomeForm::initMenu()
{
QStandardItemModel *model = new QStandardItemModel(ui->treeViewMenu);//创建模型
ui->treeViewMenu->setModel(model);//导入模型
model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("菜单导航"));
mMenuData1 << "首页" << "业务菜单" << "系统设置";
mMenuData2.push_back(QStringList());
mMenuData2.push_back(QStringList() << "3D模型" << "画图展示" << "模型3");
mMenuData2.push_back(QStringList() << "用户管理" << "系统日志");
qDebug() << mMenuData1 << mMenuData2;
for (int i = 0; i < mMenuData1.size(); ++i)
{
model->setItem(i,0,new QStandardItem(mMenuData1[i]));
for (int j = 0; j < mMenuData2[i].size(); ++j)
{
model->item(i)->appendRow(new QStandardItem(mMenuData2[i][j]));
}
}
connect(ui->treeViewMenu, &QTreeView::clicked, this, &CHomeForm::handleMenuClicked);
ui->labelTitle->setText(mMenuData1[0]);
}
页面导航跳转
void CHomeForm::handleMenuClicked(const QModelIndex &index)
{
QString menuName = index.data().toString();
qDebug() << "index = " << index.row() << index.parent().row() << menuName;
int row = index.parent().row() == -1 ? index.row() : index.parent().row();
if (index.parent().row() == -1 && mMenuData2[row].size() > 0)
{
return;
}
ui->labelTitle->setText(QString("%1 / %2").arg(mMenuData1[row]).arg(menuName));
if (menuName == "首页")
{
m3DModels->hidePage();
mCharts->hidePage();
mUsers->hidePage();
mLogs->hidePage();
}
else if (menuName == "3D模型")
{
m3DModels->showPage();
mCharts->hidePage();
mUsers->hidePage();
mLogs->hidePage();
}
else if (menuName == "画图展示")
{
m3DModels->hidePage();
mCharts->showPage();
mUsers->hidePage();
mLogs->hidePage();
}
else if (menuName == "模型3")
{
m3DModels->hidePage();
mCharts->hidePage();
mUsers->hidePage();
mLogs->hidePage();
}
else if (menuName == "用户管理")
{
m3DModels->hidePage();
mCharts->hidePage();
mUsers->showPage();
mLogs->hidePage();
}
else if (menuName == "系统日志")
{
m3DModels->hidePage();
mCharts->hidePage();
mUsers->hidePage();
mLogs->showPage();
}
resizeWidget(); //页面大小调整后,其他隐藏的页面大小也要调整
}
1.2.4.7. 创建CQCharts类
CQCharts是Qt界面设计类,继承CBaseWidget类,该类展示Qt图表功能,项目中使用该功能需要在pro文件中增加:QT += charts
//定义画图的数据结构
typedef QPair<QPointF, QString> Data;
typedef QList<Data> DataList;
typedef QList<DataList> DataTable;
namespace Ui {
class CQChartsForm;
}
class CQChartsForm : public CBaseWidget
{
Q_OBJECT
public:
explicit CQChartsForm(CBaseWidget *parent = nullptr);
~CQChartsForm();
void showPage(); //显示页面
void hidePage(); //隐藏页面
void resizeView(); //改变图表大小
//随机生成画图数据的函数
DataTable generateRandomData(int listCount, int valueMax, int valueCount) const;
//创建柱状图
QChart *createBarChart(int valueCount) const;
//创建折线图
QChart *createLineChart() const;
private slots:
void handleResults(const RstData &rstData); //接收线程返回数据的槽函数
private:
int m_listCount;
int m_valueMax;
int m_valueCount;
QList<QChartView *> m_charts;
DataTable m_dataTable;
QChartView *mLineView; //折线图
QChartView *mbarView; //柱状图
Ui::CQChartsForm *ui;
};
1.2.4.8. 创建CUsers类
CUsers是Qt界面设计类,继承CBaseWidget类,该类展示Qt表格功能,用户QTableView和自定义模型实现,用自定义模型时在pro文件中添加DEFINES += USER_MODEL
定义QTableView数据模型
class UserTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
UserTableModel(const QStringList &hreadList, QObject *parent = nullptr)
{
Q_UNUSED(parent)
mRoleList = hreadList; //表头数据
}
~UserTableModel() override
{
}
//重载函数,自定义模型需要定义,返回表格行数
int rowCount(const QModelIndex & = QModelIndex()) const override
{
return mRow;
}
//重载函数,自定义模型需要定义,返回表格列数
int columnCount(const QModelIndex & = QModelIndex()) const override
{
return mColumn;
}
//重载函数,自定义模型需要定义,设置表格表头
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
{
if(role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
//qDebug() << "[headerData]" << section << mRoleList.size();
if (section < mRoleList.size())
{
return mRoleList[section];
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
//重载函数,自定义模型需要定义,设置表格数据
QVariant data(const QModelIndex &index, int role) const override
{
if(!index.isValid())
{
return QVariant();
}
switch (role)
{
case Qt::TextColorRole:
return QColor(Qt::black);
case Qt::TextAlignmentRole:
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
case Qt::DisplayRole:
{
if (mResult.size() > index.row())
{
if (mResult[0].size() > index.column())
{
if (index.column() == 7) //状态
{
return mResult[index.row()][index.column()] == "1" ? "有效" : "无效";
}
else if (index.column() == 8) //编辑
{
return "编辑";
}
else if (index.column() == 9) //删除
{
return "删除";
}
else
{
return mResult[index.row()][index.column()];
}
}
}
//qDebug() << role << index.column() << index.row();
return QVariant();
}
case Qt::CheckStateRole:
{
return QVariant(); // 返回勾选框,如果返回QVariant()就没有勾选框
}
default:
return QVariant();
}
}
//自定义函数,返回表格行数据
QVector<QString> getRowData(int row)
{
if (row < 0 || row >= mResult.size())
{
QVector<QString> result(0);
return result;
}
return mResult[row];
}
//自定义函数,清除表格数据
void clear()
{
mResult.clear();
mRow = 0;
mColumn = 0;
}
signals:
void signalRecvhandleResult();
public slots:
void handleResults(const RstData &rstData)
{
emit signalRecvhandleResult();
beginResetModel(); // 开始刷新模型
if (rstData.retCode == 0)
{
mResult = rstData.result;
mRow = mResult.size();
qDebug() << "mRow = " << mRow;
mColumn = mRow > 0 ? mResult[0].size() : 0;
qDebug() << "mColumn = " << mColumn;
}
else
{
clear();
}
endResetModel(); // 结束刷新模型
}
private:
int mRow;
int mColumn;
QStringList mRoleList;
QVector< QVector<QString> > mResult;
};
定义用户页面类
namespace Ui {
class CUsersForm;
}
class CUsersForm : public CBaseWidget
{
Q_OBJECT
public:
explicit CUsersForm(CBaseWidget *parent = nullptr);
~CUsersForm();
void showPage(); //显示页面,发送查询数据命令
void hidePage(); //隐藏页面,清除表格数据
void setTableHead(); //设置表格表头函数
void updateTableData(const QVector< QVector<QString> > &result); //更新表格函数
private slots:
void handleResults(const RstData &rstData);//接收线程处理结果槽函数
void handleEditBtnClicked(); //行编辑槽函数
void handleDelBtnClicked(); //行删除槽函数
void handleTableClicked(const QModelIndex &index); //表格单元格点击槽函数
void on_lineEditSearch_editingFinished();//模糊搜索槽函数
void on_pbtAddUsers_clicked();
private:
Ui::CUsersForm *ui;
AddDialog *mAddDlg; //编辑用户信息弹框
};
构造函数
CUsersForm::CUsersForm(CBaseWidget *parent) :
CBaseWidget(parent),
ui(new Ui::CUsersForm)
{
ui->setupUi(this);
this->initWidgets(this, false); //初始化后,页面组件跟随页面缩放
setTableHead(); //设置表头
connect(this, &CLogsForm::operateResult, this, &CLogsForm::handleResults);//连接基类中的信号,获取页面命令处理结果
connect(ui->tabViewUsers, &QTableView::clicked, this, &CUsersForm::handleTableClicked);
mAddDlg = new AddDialog();
connect(mAddDlg, &AddDialog::operateResult, this, &CUsersForm::handleResults);
}
显示页面
void CUsersForm::showPage()
{
QVector<CmdData> argcsVec;
int count = 1000000;
for (int var = 0; var < 1; ++var)
{
CmdData argcs;
argcs.func = "getUsersData";
argcs.params["index"] = QString::number(var*count);
argcs.params["count"] = QString::number(count);
argcsVec.push_back(argcs);
}
handleCmdDataList(argcsVec);
this->show();
}
隐藏页面
void CUsersForm::hidePage()
{
#ifdef USER_MODEL
((UserTableModel*)(ui->tabViewUsers->model()))->clear();
#else
((QStandardItemModel*)(ui->tabViewUsers->model()))->clear();
#endif
this->hide();
}
设置表头
void CUsersForm::setTableHead()
{
#ifdef USER_MODEL
if (ui->tabViewUsers->model() == nullptr)
{
QStringList head;
head << "序号" << "账号" << "员工姓名" << "手机号码" << "邮箱" << "部门" << "岗位" << "账号状态" << "操作" << "操作";
UserTableModel *usrTabModel = new UserTableModel(head);
ui->tabViewUsers->setModel(usrTabModel);
}
ui->tabViewUsers->setStyleSheet("QHeaderView::section { background:green; color:white;min-height:3em;}");
ui->tabViewUsers->setGridStyle(Qt::SolidLine);
ui->tabViewUsers->horizontalHeader()->setStretchLastSection(true);
ui->tabViewUsers->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tabViewUsers->verticalHeader()->setVisible(false);
ui->tabViewUsers->setEditTriggers(QAbstractItemView::NoEditTriggers);
#else
if (ui->tabViewUsers->model() == nullptr)
{
QStandardItemModel* model = new QStandardItemModel(ui->tabViewUsers);
ui->tabViewUsers->setModel(model);
}
QStandardItemModel* model = ((QStandardItemModel*)ui->tabViewUsers->model());
QStringList head;
head << "序号" << "账号" << "员工姓名" << "手机号码" << "邮箱" << "部门" << "岗位" << "账号状态" << "操作" << "操作";
model->setHorizontalHeaderLabels(head);
ui->tabViewUsers->setStyleSheet("QHeaderView::section { background:green; color:white;min-height:3em;}");
ui->tabViewUsers->setGridStyle(Qt::SolidLine);
ui->tabViewUsers->horizontalHeader()->setStretchLastSection(true);
ui->tabViewUsers->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tabViewUsers->verticalHeader()->setVisible(false);
ui->tabViewUsers->setEditTriggers(QAbstractItemView::NoEditTriggers);
#endif
}
显示数据
void CUsersForm::updateTableData(const QVector<QVector<QString> > &result)
{
#ifdef USER_MODEL
UserTableModel *usrTabModel = ((UserTableModel*)(ui->tabViewUsers->model()));
RstData rstData;
rstData.retCode = 0;
rstData.result = result;
usrTabModel->handleResults(rstData);
#else
QStandardItemModel* model = ((QStandardItemModel*)ui->tabViewUsers->model());
setTableHead();
if (result.size() == 0) return;
int start = model->rowCount();
int col = result[0].size();
int row = result.size();
QIcon iconEdit(":/new/prefix1/images/edit.png");
QIcon iconDel(":/new/prefix1/images/edit_remove.png");
for (int i = 0; i<row; ++i)
{
QList<QStandardItem*> list;
for (int j = 0; j<col; ++j)
{
if (j == col - 3)
{
list << new QStandardItem(result[i][j] == "1" ? "有效" : "无效");
}
else if (j == col - 2)
{
list << new QStandardItem(iconEdit, "编辑");
}
else if (j == col - 1)
{
list << new QStandardItem(iconDel, "删除");
}
else
{
list << new QStandardItem(result[i][j]);
}
}
model->insertRow(i + start, list);
}
#endif
}
接收线程处理数据的槽函数
void CUsersForm::handleResults(const RstData &rstData)
{
qDebug() << "CUsersForm::handleResults" << rstData.func << rstData.retCode << rstData.msg;
if (rstData.retCode != RET_OK)
{
QMessageBox::warning(this, "提示", rstData.msg);
return;
}
if (rstData.func == "getUsersData") // 处理查询用户数据
{
qDebug() << "CUsersForm::handleResults" << rstData.result.size();
updateTableData(rstData.result);
}
else if (rstData.func == "addUsersData") // 处理增加用户数据后更新表格
{
showPage();
}
else if (rstData.func == "editUsersData")
{
QMessageBox::warning(this, "提示", rstData.msg);
mAddDlg->hide();
showPage();
}
}
使用自定义模型消耗的内存,如图:
在pro文件中注释自定义模型条件编译,#DEFINES += USER_MODEL,重新编译运行,就可以查看用Qt标准模型QStandardItemModel花费的内存,如图:
我们对比发现:使用自定义模型消耗610MB内存,使用QStandardItemModel花费2628MB内存,相差了4.3倍,所以为追求性能,最好实现自定义模型。
1.2.4.9. 创建CLogs类
CLogs是Qt界面设计类,继承CBaseWidget类,该类展示Qt表格功能,用户QTableView和QStandardItemModel实现
namespace Ui {
class CLogsForm;
}
class CLogsForm : public CBaseWidget
{
Q_OBJECT
public:
explicit CLogsForm(CBaseWidget *parent = nullptr);
~CLogsForm();
void showPage(); //显示页面,发送查询数据命令
void hidePage(); //隐藏页面,清除表格数据
void setTableHead(); //设置表格表头函数
void updateTableData(const QVector< QVector<QString> > &result); //更新表格函数
private slots:
void handleResults(const RstData &rstData); //接收线程处理结果槽函数
void on_lineEditSearch_editingFinished(); //模糊搜索槽函数
private:
Ui::CLogsForm *ui;
};
构造函数初始化
CLogsForm::CLogsForm(CBaseWidget *parent) :
CBaseWidget(parent),
ui(new Ui::CLogsForm)
{
ui->setupUi(this);
this->initWidgets(this, false); //初始化后,页面组件跟随页面缩放
setTableHead(); //设置表头
connect(this, &CLogsForm::operateResult, this, &CLogsForm::handleResults);//连接基类中的信号,获取页面命令处理结果
}
显示页面
void CLogsForm::showPage()
{
CmdData argcs;
argcs.func = "getLogsData"; //命令处理函数,查询日志信息
argcs.params["index"] = QString::number(0); //命令参数1
argcs.params["count"] = QString::number(1000000); //命令参数2
handleCmdData(argcs);
this->show();
}
隐藏页面
void CLogsForm::hidePage()
{
((QStandardItemModel*)ui->tabWidLogs->model())->clear();
this->hide();
}
设置表头
void CLogsForm::setTableHead()
{
if (ui->tabWidLogs->model() == nullptr)
{
QStandardItemModel* model = new QStandardItemModel(ui->tabWidLogs);
ui->tabWidLogs->setModel(model);
}
QStandardItemModel* model = ((QStandardItemModel*)ui->tabWidLogs->model());
model->setHorizontalHeaderLabels(QStringList() << "序号" << "用户" << "IP" << "模块" << "动作" << "内容" << "操作时间");
ui->tabWidLogs->setStyleSheet("QHeaderView::section { background:green; color:white;min-height:3em;}");
ui->tabWidLogs->setGridStyle(Qt::SolidLine);
ui->tabWidLogs->horizontalHeader()->setStretchLastSection(true);
ui->tabWidLogs->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tabWidLogs->verticalHeader()->setVisible(false);
}
显示数据
void CLogsForm::updateTableData(const QVector<QVector<QString> > &result)
{
QStandardItemModel* model = ((QStandardItemModel*)ui->tabWidLogs->model());
setTableHead();
if (result.size() == 0) return;
int start = model->rowCount();
int col = result[0].size();
int row = result.size();
for (int i = 0; i<row; ++i)
{
QList<QStandardItem*> list;
for (int j = 0; j<col; ++j)
{
list << new QStandardItem(j == 0 ? QString::number(i+1+start) : result[i][j]);
}
model->insertRow(i + start, list);
}
//qDebug() << model->rowCount() << model->columnCount();
}
接收线程处理数据的槽函数
void CLogsForm::handleResults(const RstData &rstData)
{
qDebug() << "CLogsForm::handleResults" << rstData.func << rstData.retCode << rstData.msg;
if (rstData.retCode != RET_OK)
{
QMessageBox::warning(this, "提示", rstData.msg);
return;
}
if (rstData.func == "getLogsData") //处理用户登录结果
{
qDebug() << "CLogsForm::handleResults" << rstData.result.size();
updateTableData(rstData.result);
}
}
1.3. 源码文件
后台源码:https://download.csdn.net/download/yyt593891927/12676387
资源解压密码:dingba
默认用户名:admin
默认密码:admin
1.4. 后记
本文完整讲述了利用Qt+mysql搭建系统,下一章介绍用qml+mysql搭建系统。
————————————————
版权声明:本文为CSDN博主「丁爸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yyt593891927/article/details/107712154
更多推荐
所有评论(0)