Qt跨平台开发demo(适用萌新)

最近需要参与一款Qt跨平台的软件开发,在此之前,特把基础信息做学习和梳理,仅供参考。

所使用的技术和版本情况如下:

  • 虚拟机:VMware 16.2.5
  • 操作系统:ubuntu-20.04.6-desktop-amd64:
  • Mysql数据库 8.0.36
  • Workbench (mysql-workbench-community_8.0.29-1ubuntu20.04_amd64.deb)
  • QT 5.12.12(qt-opensource-linux-x64-5.12.12.run)

ps:有人问为什么不用VirtualBox、GNOME Boxes,或者其他Qt、mysql版本问题,前者是因为个人习惯,后者是因为项目要求。

1、开发环境搭建

参考这篇

2、MVC简介

MVC模式是软件工程中常见的一种软件架构模式,该模式把软件系统(项目)分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

使用MVC模式有很多优势,例如:

  • 简化后期对项目的修改、扩展等维护操作;

  • 使项目的某一部分变得可以重复利用;使项目的结构更加直观。

具体来讲,MVC模式可以将项目划分为模型(M)、视图(V)和控制器(C)三个部分,并赋予各个部分不同的功能,方便开发人员进行分组。

**(1)模型(Model):**模型持有所有的数据、状态和程序逻辑。模型接受视图数据的请求,并返回最终的处理结果。

**(2)视图(View):**负责界面的显示,以及与用户的交互功能,例如表单、网页等。

**(3)控制器(Controller):**可以理解为一个分发器,用来决定对于视图发来的请求,需要用哪一个模型来处理,以及处理完后需要跳回到哪一个视图。即用来连接视图和模型。

实际开发中,通常用控制器对客户端的请求数据进行封装(如将form表单发来的若干个表单字段值,封装到一个实体对象中),然后调用某一个模型来处理此请求,最后再转发请求(或重定向)到视图(或另一个控制器)。

在这里插入图片描述

3、代码设计与实现

1、框架构成

一个基于C++和QML的跨平台项目框架通常包含以下几个主要组成部分:后端C++逻辑、QML前端界面、信号与槽机制进行通信,以及可能的数据存储(如数据库)。下面是对这个框架构成的简单描述:

1. 后端C++逻辑

  • C++类库:C++代码部分通常包含一系列类,这些类封装了应用程序的核心逻辑。这些类可能包括数据处理、算法实现、网络通信、文件操作等。
  • 数据库访问:持久化存储数据,C++代码需包含与数据库交互的逻辑。这通常涉及使用数据库API或ORM(对象关系映射)库来执行查询、插入、更新和删除操作。
  • 业务逻辑:C++代码包含应用程序的业务逻辑,即根据用户需求和数据状态执行的操作。

2. QML前端界面

  • QML文件:QML是一种用于描述用户界面的声明式语言,它类似于HTML和CSS的结合。QML文件定义了应用程序的外观和布局,包括窗口、按钮、文本框等界面元素。
  • 界面元素:QML文件中包含各种界面元素,这些元素通过属性和信号与C++代码进行交互。例如,一个按钮的点击事件可以触发一个信号,该信号被C++代码中的槽函数捕获并处理。
  • 样式和主题:QML还支持自定义样式和主题,以便轻松更改应用程序的外观。

3. 信号与槽机制进行通信

  • 信号:在Qt框架中,信号是对象在特定事件发生时发出的一种通知。QML界面元素和C++对象都可以发出信号。
  • :槽是响应信号的函数或方法。当信号被发出时,与之关联的槽函数将被调用。这种机制允许QML界面与C++后端逻辑进行无缝通信。
  • 连接信号与槽:在应用程序中,需要显式地将信号连接到槽。这可以在C++代码中完成,也可以在QML文件中使用Qt的内置函数(如Connections元素)完成。

4. 应用程序集成

  • 主函数:C++代码中的主函数(通常是main.cpp)负责初始化Qt应用程序,加载QML界面,并将它们与C++后端逻辑集成在一起。
  • 资源文件:为了管理应用程序中的资源(如QML文件、图像、字体等),你可以使用Qt的资源系统。资源文件(通常是.qrc文件)定义了这些资源的路径和属性。
  • 编译和部署:使用Qt的构建系统(如qmake或CMake)编译应用程序,并确保在目标平台上部署所有必要的依赖项和运行时库。

通过这种框架,你可以开发出既具有强大功能又具有良好用户体验的跨平台应用程序。C++后端提供了灵活性和性能,而QML前端则提供了直观和易于定制的用户界面。

如果是和我一样的QML小白,推荐看两个视频:

数据库相关操作,包含事务命令:UP:爱编程的大丙

QML教程(P20-23,QML与C++交互):UP:落雨薄青衫

2、代码部分

先贴库:gitee

1、.pro文件

Qt项目的.pro文件(也称为qmake项目文件)。这个文件用于描述如何构建Qt项目,并包含了编译项目所需的各种设置和指令。下面我将逐一解释这个文件中的各个部分:

这是一个Qt项目的.pro文件(也称为qmake项目文件)。这个文件用于描述如何构建Qt项目,并包含了编译项目所需的各种设置和指令。主要关注前面:

  1. QT += quick qml sql quickcontrols2

    指定了项目需要使用的Qt模块。这里指定了quick(用于Qt Quick框架),qml(QML支持),sql(数据库支持)和quickcontrols2(Qt Quick Controls 2 UI框架)。

  2. CONFIG += c++11

    指示qmake使用C++11标准来编译项目。

总的来说,这个.pro文件为Qt项目提供了构建和安装的详细信息。可以根据项目的具体需求来修改。

2、头文件

DbConnector主要处理数据库:

class DbConnector : public QObject
{Q_OBJECT
public:explicit DbConnector(QObject *parent = nullptr);~DbConnector();static DbConnector * getInstance();void createSql();	//用于初始化数据库(打开,连接),在构造函数内调用void closeSql();  //用于关闭数据库,在析构函数内调用Q_INVOKABLE QSqlDatabase getDb();
private:QSqlDatabase db;	//定义一个数据库变量
};

MyListModel主要处理自定义模型的数据:

class MyListModel : public QAbstractListModel
{Q_OBJECT
public:enum MyRoleName{Name = Qt::DisplayRole + 1,Value};explicit MyListModel(QObject *parent = nullptr);static MyListModel * getInstance();Q_INVOKABLE bool select();void refreshData();int rowCount(const QModelIndex &parent = QModelIndex()) const override;QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;QHash<int,QByteArray> roleNames() const override;Q_INVOKABLE void addData(QString s);Q_INVOKABLE void updateData(int id,QString s);Q_INVOKABLE void onEnterPressed(int id,QString s);public slots:void addSlot(QString s);void updateSlot(int id,QString s);void onEnterPressedSlot(int id,QString s);
private:QList<QString> m_data;
};

3、源文件

DbConnector:

数据库连接

void DbConnector::createSql()
{db = QSqlDatabase::addDatabase("QMYSQL");//mysql需要自己编译,没有的话查看我上篇的解决方案db.setHostName("localhost");//自己填db.setUserName("username");//自己填db.setDatabaseName("DatabaseName");//自己填db.setPassword("密码");//自己填db.setPort(3306);//自己查if(!db.open()){qDebug()<<"fail :"<<db.lastError().text();}else{qDebug()<<"open db success";}
}

添加逻辑:

void MyListModel::addSlot(QString s)
{addData(s);refreshData();
}
void MyListModel::addData(QString s)
{QSqlQuery query;QString sql = "INSERT INTO person (name) VALUES (:name)";// 使用prepare()方法来准备SQL语句,并使用bindValue()来绑定参数query.prepare(sql);query.bindValue(":name", s);// 执行SQL语句if (!query.exec()){qDebug() << "Failed to insert name:" << query.lastError().text();}else{qDebug() << "Successfully inserted name:" << s;}
}
void MyListModel::refreshData()
{beginResetModel(); // 视图模型更改if(select()){qDebug()<<"refresh data success";}else{qDebug()<<"refresh data failed";}endResetModel();
}

更新逻辑:

void MyListModel::updateSlot(int id,QString s)
{updateData(id,s);int row = id;// 通知QML该元素已更改emit dataChanged(index(row, 0), index(row, 0));refreshData();
}
void MyListModel::updateData(int id, QString s)
{id++;QSqlQuery query;QString sql = "UPDATE person SET name = :newName WHERE id = :id";// 使用prepare()方法来准备SQL语句,并使用bindValue()来绑定参数query.prepare(sql);query.bindValue(":newName", s);query.bindValue(":id", id);// 执行SQL语句if (!query.exec()){qDebug() << "Failed to update name for id:" << id << "Error:" << query.lastError().text();return;}qDebug() << "Successfully updated name for id:" << id;
}

4、QML文件

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12Window {id:windowwidth: 640height: 480visible: truetitle: qsTr("Hello World")//信号signal addSig(string s)signal updateSig(int id,string s)signal onEnterPressedSig(int id,string s)ComboBox{id:comboBoxx:10y:10z:1width:150height: 40model:MyListModelcurrentIndex: 0font.pointSize: 12editable: true //允许编辑delegate:ItemDelegate{id:delegatewidth:comboBox.widthheight: comboBox.heightcontentItem: Text{text:nameanchors.fill:parentcolor:"black"font:comboBox.fontelide:Text.ElideRightverticalAlignment: Text.AlignVCenter}highlighted: index === comboBox.highlightedIndex//悬浮}Component.onCompleted:{comboBox.editText = "请选择"addSig.connect(MyListModel.addSlot)updateSig.connect(MyListModel.updateSlot)onEnterPressedSig.connect(MyListModel.onEnterPressedSlot)}Button{x:50y:50id:btntext:"新增"onClicked:{var editText = comboBox.editText;addSig(editText);comboBox.currentIndex = MyListModel.rowCount()-1;console.log("currentIndex is ",comboBox.currentIndex);}}Button{x:50y:100id:btn2text:"修改"onClicked:{var currentIndex = comboBox.currentIndex-1;var editText = comboBox.editText;updateSig(currentIndex,editText);}}}
}

Button实现起来比较简单一点,也更符合正常的逻辑。
在这里插入图片描述

4、总结

整体项目不难,但是“五脏俱全”,包含了一个QT跨平台项目最基本的知识点,适合新人练手。
希望大神们多多批评指正,我也是刚上手。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/325694.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

纯血鸿蒙APP实战开发——数字滚动动效实现

介绍 本示例主要介绍了数字滚动动效的实现方案。 该方案多用于数字刷新&#xff0c;例如页面刷新抢票数量等场景。 效果图预览 使用说明&#xff1a; 下拉页面刷新&#xff0c;数字进行刷新。 实现思路 通过双重ForEach循环分别横向、纵向渲染数字。 Row() {ForEach(this…

服装店会员管理系统结合小程序商城帮你挖掘出潜在客户

在现代社会&#xff0c;随着科技的不断进步和人们消费习惯的变化&#xff0c;传统的服装店已经不再能够满足消费者的需求。为了更好地服务客户&#xff0c;提升销售业绩&#xff0c;许多服装店开始引入会员管理系统&#xff0c;并结合小程序商城&#xff0c;实现线上线下的无缝…

AJAX前端与后端交互技术知识点以及案例

Promise promise对象用于表示一个异步操作的最终完成&#xff08;或失败&#xff09;及其结果值 好处&#xff1a; 逻辑更清晰了解axios函数内部运作机制成功和失败状态&#xff0c;可以关联对应处理程序能解决回调函数地狱问题 /*** 目标&#xff1a;使用Promise管理异步任…

C++ int 学习

在C语言中 & 是取地址符号&#xff1b; 在C中有 int& 这样的&#xff0c;这里的&不是取地址符号&#xff0c;而是引用符号&#xff1b; 引用是C对C的一个补充&#xff1b; 变量的引用就是变量的别名&#xff0c;讲的通俗一点就是另外一个名字&#xff1b; a的值…

鸿蒙开发接口Ability框架:【(AbilityContext)】

AbilityContext AbilityContext是Ability的上下文环境&#xff0c;继承自Context。 AbilityContext模块提供允许访问特定于ability的资源的能力&#xff0c;包括对Ability的启动、停止的设置、获取caller通信接口、拉起弹窗请求用户授权等。 说明&#xff1a; 本模块首批接口…

040——移植数据库sqlite3到i.mx6ull

目录 一、下载 二、移植数据库 三、测试sqlite3 一、下载 SQLite Download Page 暂时先下载最新版的试试&#xff0c;我们以前其实在ubuntu上直接使用过 嵌入式数据库sqlite3_常见的嵌入式数据库-CSDN博客 当时我把常用的操作和怎么使用记录下来了 现在把他移植到开发板…

Android11 InputManagerService启动流程分析

InputManagerService在systemserver进程中被启动 //frameworks\base\services\java\com\android\server\SystemServer.java t.traceBegin("StartInputManagerService"); inputManager new InputManagerService(context);//1 t.traceEnd(); //省略 //注册服务 Servi…

C++11:常用语法汇总

目录 &#x1f341;统一的列表初始化 { }initializer_list &#x1f341;decltype 推导表达式类型&#x1f341;可变参数模板解析可变参数包方法一方法二 &#x1f341;lambda 表达式捕捉列表的使用运用场景举例lambda表达式 与 函数对象 &#x1f341;统一的列表初始化 { } 在…

2024最新商业视频打赏系统源码 多套模板 有代理后台 已对接支付

简介&#xff1a; 2024最新商业视频打赏系统源码 多套模板 有代理后台 已对接支付 图片&#xff1a; 源码下载

【Python从入门到进阶】54、使用Python轻松操作SQLite数据库

一、引言 1、什么是SQLite SQLite的起源可以追溯到2000年&#xff0c;由D. Richard Hipp&#xff08;理查德希普&#xff09;所创建。作为一个独立的开发者&#xff0c;Hipp在寻找一个能够在嵌入式系统中使用的轻量级数据库时&#xff0c;发现现有的解决方案要么过于庞大&…

并发-守护线程setDaemon()

目录 为什么存在 什么是守护线程 创建守护线程 在使用守护线程时需要注意以下几点 可以使用isDaemon()方法来检查线程是否是守护线程 例1&#xff1a;上面提到当JVM中只剩下守护线程的时候&#xff0c;JVM就会退出&#xff0c;那么写段代码测试下 例2&#xff1a;thread…

练习队列的相关操作:循环队列

1. 思路解析 循环队列就是在只有有限的空间时使用队列实现循环存储数据&#xff0c;有双向链表和数组两种选择&#xff0c;这里我们使用数组实现循环队列&#xff08;因为链表我不会 >-<&#xff09; 2. 相关函数及其实现 2.1 判空与判满 判空&#xff1a;直接返回头尾…

docker(四):数据卷

数据卷 卷的设计目的就是数据的持久化&#xff0c;完全独立于容器的生存周期&#xff0c;因此Docker不会在容器删除时删除其挂载的数据卷。 1、docker run docker run -it --privilegedtrue -v /宿主机绝对路径目录:/容器内目录 镜像名2、挂载注意事项 --privilegedtru…

【C++】二叉搜索树(手撕插入、删除、寻找)

一、什么是二叉搜索树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左…

OSError: [WinError 1455] 页面文件太小,无法完成操作 的问题

实质问题是报错&#xff1a;caffe2_detectron_ops.dll“ or one of its dependencies 还需要安装一个包&#xff1a; pip install intel-openmp 安装之后顺利测试通过。

Tomcat7+ 弱口令 后台getshell漏洞

1 漏洞背景 Tomcat 是一个流行的开源Web应用服务器&#xff0c;用于部署和运行Java Web应用程序。Tomcat 7 版本中存在一个安全隐患&#xff0c;即默认的管理员密码可能较弱或者未被修改&#xff0c;攻击者可以利用这一漏洞登录到Tomcat的管理后台&#xff0c;并上传恶意的WAR…

LeetCode100题总结

LeetCode100题总结 前言LeetCode100题总结题型梳理双指针11. 盛最多水的容器234.回文链表75.颜色分类206.反转链表142.环形链表215.三数之和 滑动窗口3. 无重复字符的最长子串209. 长度最小的子数组438. 找到字符串中所有字母异位词 广搜102. 二叉树的层序遍历200. 岛屿数量617…

轮转数组 与 消失的数字

轮转数组 思路一 创建一个新内存空间&#xff0c;将需轮转的数依次放入&#xff0c;之后在把其它数放入 代码&#xff1a; void rotate(int* nums, int numsSize, int k) {k k % numsSize;// 确定有效的旋转次数if(k 0)return;int* newnums (int*)malloc(sizeof(int) * nu…

2024数据分析管理、数字经济与教育国际学术会议(ICDAMDEE2024)

2024数据分析管理、数字经济与教育国际学术会议(ICDAMDEE2024) 会议简介 2024年数据分析管理、数字经济和教育国际学术会议&#xff08;ICDAMDEE 2024&#xff09;将在武汉举行。会议不仅展示了来自世界各地的研究专家围绕数据分析管理、数字经济和教育的最新科研成果&#xf…

纯血鸿蒙APP实战开发——Grid和List内拖拽交换子组件位置

Grid和List内拖拽交换子组件位置 介绍 本示例分别通过onItemDrop()和onDrop()回调&#xff0c;实现子组件在Grid和List中的子组件位置交换。 效果图预览 使用说明&#xff1a; 拖拽Grid中子组件&#xff0c;到目标Grid子组件位置&#xff0c;进行两者位置互换。拖拽List中子…