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

news2024/11/19 1:32:29

最近需要参与一款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.12


Window {
    id:window
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    //信号
    signal addSig(string s)
    signal updateSig(int id,string s)
    signal onEnterPressedSig(int id,string s)

    ComboBox{
        id:comboBox
        x:10
        y:10
        z:1
        width:150
        height: 40
        model:MyListModel
        currentIndex: 0
        font.pointSize: 12
        editable: true //允许编辑

        delegate:ItemDelegate
        {
            id:delegate
            width:comboBox.width
            height: comboBox.height
            contentItem: Text{
                text:name
                anchors.fill:parent
                color:"black"
                font:comboBox.font
                elide:Text.ElideRight
                verticalAlignment: Text.AlignVCenter
            }
            highlighted: index === comboBox.highlightedIndex//悬浮
        }

        Component.onCompleted:
        {
            comboBox.editText = "请选择"
            addSig.connect(MyListModel.addSlot)
            updateSig.connect(MyListModel.updateSlot)
            onEnterPressedSig.connect(MyListModel.onEnterPressedSlot)
        }

        Button
        {
            x:50
            y:50
            id:btn
            text:"新增"
            onClicked:
            {
                var editText = comboBox.editText;
                addSig(editText);
                comboBox.currentIndex = MyListModel.rowCount()-1;
                console.log("currentIndex is ",comboBox.currentIndex);
            }
        }

        Button
        {
            x:50
            y:100
            id:btn2
            text:"修改"
            onClicked:
            {
                var currentIndex = comboBox.currentIndex-1;
                var editText = comboBox.editText;
                updateSig(currentIndex,editText);
            }
        }
    }
}

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

4、总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在阿里云K8S容器中,部署websocket应用程序的总结

一、背景 有一个websocket应用程序&#xff0c;使用spring boot框架开发&#xff0c;http端口号是6005&#xff0c;提供的是websocket服务&#xff0c;所以它还监听一个8889端口的tcp协议。 现在要把它部署到阿里云的k8s容器里&#xff0c;本文着重描述service层的配置。 因…

不会pdf修改编辑文字怎么办?看完秒懂

不会pdf修改编辑文字怎么办&#xff1f;在日常生活中&#xff0c;PDF文件已成为我们工作、学习不可或缺的一部分。然而&#xff0c;很多人对PDF文件的编辑操作感到困惑&#xff0c;尤其是修改其中的文字。今天&#xff0c;我们就来详细解析一下&#xff0c;不会PDF修改编辑文字…

C++进阶之路:探索访问限定符、封装与this指针的奥秘(类与对象_上篇)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

鸿蒙开发之 if/else:条件渲染

ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态&#xff0c;使用if、else和else if渲染对应状态下的UI内容。 使用规则 支持if、else和else if语句。if、else if后跟随的条件语句可以使用状态变量。允许在容器组件内使用&#xff0c;通过条件渲染语句构建不同的子…

数据结构--图。

在前面&#xff0c;我们学习了线性表和树&#xff0c;而接下来我们要学习的图相较于他们就更加复杂。 目录 一.图的有关概念 一.图的有关概念 1.定义 图(graph)G由两个集合V和E组成&#xff0c;记为G&#xff08;VE)。V是顶点的有穷非空集合;E是边的集合,边是V中顶点的无序对…

02-单片机商业项目编程,从零搭建低功耗系统设计

一、本文内容 上一节《01-单片机商业项目编程&#xff0c;从零搭建低功耗系统设计-CSDN博客》已经对事件驱动原理有个基本了解&#xff0c;本节主要就是如何将事件写的更规范&#xff0c;而不是用t_flag这样的标记&#xff0c;写多了可读性也不强&#xff1b;本节结尾总结将提出…

【探索Java编程:从入门到入狱】Day5

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

《ESP8266通信指南》13-Lua 简单入门(打印数据)

往期 《ESP8266通信指南》12-Lua 固件烧录-CSDN博客 《ESP8266通信指南》11-Lua开发环境配置-CSDN博客 《ESP8266通信指南》10-MQTT通信&#xff08;Arduino开发&#xff09;-CSDN博客 《ESP8266通信指南》9-TCP通信&#xff08;Arudino开发&#xff09;-CSDN博客 《ESP82…

驱动比例线圈功率放大器

驱动比例线圈功率放大器是一种用于控制比例电磁铁的电流大小实现被控设备的位移&#xff0c;采用高性能的嵌入式32位微处理器作为运算核心&#xff0c;这些微处理器具有高速指令运行能力&#xff0c;电源24VDC驱动&#xff0c;输入指令兼容性强&#xff0c;输出电流大小可调&am…

云打印怎么保护用户的隐私?

随着互联网的发展&#xff0c;在当下的网络环境下&#xff0c;用户的隐私越来越难以保证安全。特别是对于打印业务来说&#xff0c;盗取用户文件、转卖客户信息的内容时有发生。那么我们作为出色的云打印服务商&#xff0c;该如何保证用户的隐私呢&#xff1f;今天就来给大家介…

正点原子Linux学习笔记(五)FrameBuffer 应用编程

FrameBuffer 应用编程 19.1 什么是 FrameBuffer19.2 LCD 的基础知识19.3 LCD 应用编程介绍使用 ioctl()获取屏幕参数信息使用 mmap()将显示缓冲区映射到用户空间 19.4 LCD 应用编程练习之 LCD 基本操作19.5 LCD 应用编程练习之显示 BMP 图片在 LCD 上显示 BMP 图像在开发板上测…

Java的BIO/NIO/AIO

1. Java中的BIO、NIO和AIO的基本概念及其主要区别 BIO (Blocking I/O): 传统的同步阻塞I/O模型。每个连接创建成功后都需要一个线程来处理&#xff0c;如果连接没有数据可读&#xff0c;则线程会阻塞在读操作上。这种模型简单易理解&#xff0c;但在高并发环境下会消耗大量系统…

【excel】数据非数值导致排序失效

场景 存在待排序列的数值列&#xff0c;但排序失效&#xff0c;提示类型有问题&#xff1a; 解决 选中该列&#xff0c;数据→分列 而后发现提示消失&#xff0c;识别为数字&#xff0c;可正常排序。

ERROR 1045 (28000) Access denied for user ‘root‘@‘IP‘(using password YES/NO)

查看权限 要查看MySQL用户的权限&#xff0c;您可以使用SHOW GRANTS语句。这将列出用户的权限&#xff0c;包括授予的权限和可以授予其他用户的权限。 以下是查看当前用户权限的SQL命令&#xff1a; SHOW GRANTS; 如果您想查看特定用户的权限&#xff0c;可以使用以下命令&…

【漏洞复现】金和OA FileDownLoad接口处存在任意文件读取漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

销售订单分析表-CX_SY_CONVERSION_NO_NUMBER异常

销售订单分析表-CX_SY_CONVERSION_NO_NUMBER异常 这里记录一次发生过的异常报错&#xff0c;和找到原因的过程&#xff1a;

Springboot+Vue项目-基于Java+MySQL的流浪动物管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

华为OD机试 - 计算三叉搜索树的高度 - 二叉树(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

每日Attention学习1——Parallel Aggregation Pyramid Pooling Module

模块出处 [CVPR 23] [link] [code] PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers 模块名称 Parallel Aggregation Pyramid Pooling Module (PAPPM) 模块作用 多尺度特征提取&#xff0c;更大感受野 模块结构 模块代码 import torch imp…

C++聊天服务器数据库创建

创建数据库chat show databases&#xff1a;展示所有的数据库 create database chat&#xff1a;创建一个数据库chat use chat&#xff1a;使用数据库 创建表User、Friend、AllGroup、GroupUser、OfflineMessage 表User包含&#xff1a;用户id、用户名、用户密码、当前登录…