Qt+mysql搭建系统_qt做数据库应用系统开发,2024年最新阿里P8亲自讲解

53 阅读9分钟

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。 img img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

};


构造函数初始化



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 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 DataList; typedef QList 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 > 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 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 > &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();
}

}


使用自定义模型消耗的内存,如图:  
 ![在这里插入图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fa41d9faa22a47708a1208cac3606f69~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771322084&x-signature=j%2BzcHQvEZnoIrMBqzyqSS0QuZKE%3D)  
 在pro文件中注释自定义模型条件编译,#DEFINES += USER\_MODEL,重新编译运行,就可以查看用Qt标准模型QStandardItemModel花费的内存,如图:  
 ![在这里插入图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c186221d02994deb9c478d260e6e7c60~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771322084&x-signature=KopJ7d31kEpHJzA1MZcdPgSEe68%3D)  
 我们对比发现:使用自定义模型消耗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(); //设置表头

img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取