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

3 篇文章 0 订阅

最近需要参与一款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跨平台项目最基本的知识点,适合新人练手。
希望大神们多多批评指正,我也是刚上手。

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MQTT是一种轻量级的消息传输协议,适合于低带宽、高延迟和不稳定网络环境下的即时通讯。QT是一种平台的应用程序开发框架,支持图形用户界面开发、数据库操作、网络应用等。 为了开发MQTT Demo,需要先安装MQTT客户端库,例如MQTT C++客户端库mosquitto_cpp。然后在QT工程中添加mosquitto_cpp头文件和库文件,设置相关编译器选项,并编写业务逻辑。 MQTT Demo主要包括如下功能: 1. 连接MQTT服务器:包括设置MQTT服务器地址、端口号、用户名和密码等参数,建立MQTT连接。 2. 订阅主题:设计订阅主题,过滤器和QoS等参数,实现接收服务器端发来的消息。 3. 发布消息:设置发布消息的主题、内容和QoS等参数,通过MQTT客户端发送数据到服务器端。 4. 断开连接:在程序结束前,对MQTT连接进行正常关闭。 在开发过程中,需要注意以下几点: 1. 异步消息回调机制:mosquitto_cpp提供了异步消息回调机制,需要在类继承mosqpp::mosquittopp时,重载on_message函数,实现接收MQTT消息。 2. 线程安全问题:MQTT连接需要在独立线程中执行,避免阻塞界面操作。 3. 数据结构设计:使用Qt提供的数据结构,如QByteArray、QString等,方便消息的编解码操作。 MQTT Demo开发需要较强的C++编程能力和熟练运用Qt开发工具,若要实现更为复杂的功能,还需要深入掌握MQTT协议和mosquitto_cpp库的使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明教张公子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值