本文介绍Qt+vue实现一个windows桌面应用程序,效果图如下:
注意:Qt版本5.15,编译器要选MSVC xxxx(本文选:MSVC2019 64bit)。Qt web相关模块在windows系统不支持MinGw编译器。
QWebEngineView:加载和显示html页面
QWebChannel:负责html和Qt交互
QWidget:显示窗口页面
QThread:创建线程异步处理页面请求
QJson…:json数据处理
由于页面是由Vue实现的,页面需要作为资源文件加载,我们创建一个资源文件src.qrc,如图
把前端vue打包生成的html添加到src.qrc里面,
项目目录结构如上图,文件和目录的说明如下:
Common:Qt类,单例类,注册元类型和定义交互数据结构
CWorker:Qt类,在线程中运行,异步处理html页面请求
main.cpp:项目入口文件
widget.cpp:QML文件,登录页面
Forms:Qt界面文件
Resources:Qt资源文件目录
下面我们来创建上面的列表类文件
Common类是一个单例类,有以下功能:
头文件
//解决QT+VS中文乱码问题
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif
enum RET_CODE {
RET_OK = 0,
RET_DBERR_OPEN,
RET_DBERR_RUN,
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;
class MyCommon : public QObject
{
Q_OBJECT
public:
explicit MyCommon(QObject *parent = nullptr);
~MyCommon();
static MyCommon *instance();
static QString GetJsonData(const RstData &rstData);
static QString QJson2QString(const QJsonObject &dataObj);
static QString QJson2QString(const QJsonArray &dataObj);
private:
static MyCommon *self;//单例模式
static QTime mTime;
};
#endif // CCOMMON_H
源文件
#include "ccommon.h"
#include
#include
MyCommon *MyCommon::self = nullptr;
QTime MyCommon::mTime;
QStringList RET_MSG = QStringList() << "成功" << "数据库查询打开失败" << "SQL执行失败" << "参数错误"
<< "方法不存在" << "处理类型不存在";
MyCommon::MyCommon(QObject *parent) : QObject(parent)
{
//注册元类型:主要是在定义信号槽的时候,传递的参数类型不一定是QT所识别的
qRegisterMetaType<CmdData>("CmdData");
qRegisterMetaType<RstData>("RstData");
}
MyCommon::~MyCommon()
{
if (self != nullptr)
{
delete self;
}
}
MyCommon *MyCommon::instance()
{
if(!self)
{
self = new MyCommon();
}
return self;
}
QString MyCommon::GetJsonData(const RstData &rstData)
{
mTime.start();
QJsonObject dataObj;
QJsonObject jsObjChild;
QJsonArray dataArray;
dataObj.insert("code", rstData.retCode);
dataObj.insert("msg", rstData.msg);
dataObj.insert("func", rstData.func);
int row = rstData.result.size();
for (int i = 0; i<row; ++i)
{
dataArray.append(QJsonArray::fromStringList(rstData.result[i].toList()));
}
dataObj.insert("data", dataArray);
qDebug() << "-----------elapsed: " << mTime.elapsed();
qDebug() << rstData.result << QJson2QString(dataObj);
return QJson2QString(dataObj);
}
QString MyCommon::QJson2QString(const QJsonObject &dataObj)
{
QJsonDocument document(dataObj);
QByteArray byteArray =document.toJson(QJsonDocument::Compact);
QString strJson(byteArray);
return strJson;
}
QString MyCommon::QJson2QString(const QJsonArray &dataObj)
{
QJsonDocument document(dataObj);
QByteArray byteArray =document.toJson(QJsonDocument::Compact);
QString strJson(byteArray);
return strJson;
}
Widget是继承QWidget,有以下功能:
头文件
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include "Common/ccommon.h"
class Core : public QObject
{
Q_OBJECT
public:
explicit Core(QObject *parent = nullptr);
~Core()
{
mWorkerThread.quit();
mWorkerThread.wait();
}
// 定义供html页面调用的函数时,需要加上Q_INVOKABLE,否则html页面会找不到定义的函数
Q_INVOKABLE void handleCmd(const QString &func, const QStringList &keys,
const QStringList &values);
signals:
void operate(const int type, const QString &func, const QString &cmd);
void operateResult(const QString &result);
public slots:
void handleResults(const RstData &rstData);
private:
QThread mWorkerThread;
};
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
Core mCore; // 定义全局的,否则程序运行会出错,js里面也找不到Core里面定义的函数
};
#endif // WIDGET_H
源文件
#include "widget.h"
#include "ui_widget.h"
#include
#include
#include "CWorker/worker.h"
Core::Core(QObject *parent) : QObject(parent)
{
Worker *worker = new Worker;
worker->moveToThread(&mWorkerThread);
connect(&mWorkerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Core::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Core::handleResults); // Qt接口
mWorkerThread.start();
}
void Core::handleCmd(const QString &func, const QStringList &keys, const QStringList &values)
{
qDebug() << func << keys << values;
QString cmd = "0";
if (func == "selectFile")
{
QFileDialog dialog;
QString fileName = dialog.getOpenFileName(NULL,
tr("selectFile"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"));
}
else if (func == "selectDir")
{
QFileDialog dialog;
dialog.setFileMode(QFileDialog::Directory);
QString fileName = dialog.getOpenFileName(NULL,
tr("selectDir"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"));
}
else
{
RstData rstData;
if (keys.size() != values.size() || values.size() != 2)
{
rstData.retCode = RET_PARAMERR;
rstData.msg = RET_MSG[rstData.retCode];
emit operateResult(MyCommon::GetJsonData(rstData));
return;
}
if (values[0] == "admin" && values[1] == "admin")
{
cmd = "1";
}
}
emit operate(WORK_DB_QUERY, func, cmd);
}
void Core::handleResults(const RstData &rstData)
{
qDebug() << "[handleResults]result.size()=" << rstData.func << ","
<< rstData.retCode << "," << rstData.msg;
emit operateResult(MyCommon::GetJsonData(rstData));
}
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QString title = "QWebEngineView+vue开发桌面应用程序";
setWindowTitle(title);
ui->preview->setContextMenuPolicy(Qt::NoContextMenu);
// 定义交互类,通过channel与html交互
QWebChannel *channel = new QWebChannel(this);
channel->registerObject(QStringLiteral("core"), &mCore);
ui->preview->page()->setWebChannel(channel);
ui->preview->setUrl(QUrl("qrc:/sources/html/index.html"));
}
Widget::~Widget()
{
delete ui;
}
CWorker是Qt类,有以下功能:
#ifndef WORKER_H
#define WORKER_H
#include
#include "Common/ccommon.h"
enum WORK_TYPE {
WORK_DB_QUERY = 0,
WORK_DB_RUN
};
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
signals:
void resultReady(const RstData &rstData);
public slots:
void doWork(const int type, const QString &func, const QString &cmd);
private:
};
#endif // WORKER_H
源文件
#include "worker.h"
#include
Worker::Worker(QObject *parent) : QObject(parent)
{
}
void Worker::doWork(const int type, const QString &func, const QString &cmd)
{
qDebug() << "[Worker::doWork]type=" << type << "func=" << func;
RstData rstData;
rstData.func = func;
rstData.retCode = RET_OK;
rstData.msg = RET_MSG[rstData.retCode];
if (type == WORK_DB_QUERY)
{
if (cmd == "0")
{
rstData.retCode = RET_PARAMERR;
rstData.msg = "用户名或密码错误";
}
}
else if (type == WORK_DB_RUN)
{
}
else
{
rstData.retCode = RET_NOWORKTYPE;
rstData.msg = RET_MSG[rstData.retCode];
}
emit resultReady(rstData); // Qt接口
}
main.cpp是项目的入口文件,有以下功能:
源文件
int main(int argc, char *argv[])
{
QCoreApplication::setOrganizationName("丁爸webenginewidgets测试例子");
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication a(argc, argv);
MyCommon::instance();
Widget w;
w.show();
return a.exec();
}
源码地址:https://download.csdn.net/download/yyt593891927/12838793
默认用户名:admin
默认密码:admin
本文介绍了Qt+vue实现一个windows桌面应用程序,下一章介绍《Qt+vue开发桌面应用程序(二)Vue部分介绍》