一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

新建工程

使用clion 新建工程

使用clion 创建一个QT工程,注意其中Qt CMake前缀路径的选择:

 新建好的工程如下:

 这时,如果直接编译会报一个错误:

经过谷歌查询,这个错误是由于CMake指定了一个Debug版本的QT,但是我并没有找到所谓的Debug版本的下载方式,所以这里CMake我们需要自己写,来规避一些错误。

修改cmake

打开CMakeLists.txt,修改如下:

 1 cmake_minimum_required(VERSION 3.21) #cmake最低版本
 2 project(QtWindowsHost) #工程名
 3 
 4 set(CMAKE_CXX_STANDARD 14) #C++标准
 5 # 开启QT用于预处理的组件
 6 set(CMAKE_AUTOMOC ON) 
 7 set(CMAKE_AUTORCC ON)
 8 set(CMAKE_AUTOUIC ON)
 9 # 设置cmake模块的查询目录,注意这里的路径,到mingw路径即可
10 set(CMAKE_PREFIX_PATH C:/Qt/5.14.2/mingw73_64)
11 # 查找QT的模块
12 find_package(Qt5 COMPONENTS
13         Core
14         Gui
15         Widgets
16         REQUIRED)
17 # 添加源文件
18 add_executable(QtWindowsHost
19         main.cpp
20         )
21 # 添加模块
22 target_link_libraries(QtWindowsHost
23         Qt5::Core
24         Qt5::Gui
25         Qt5::Widgets
26         )

以上模板仅供参考。

 这时候我们再去编译,就可以看到编译成功了,生成了一个默认的窗口:

项目设置

这里我们一切从简,只要一个简单的接收发送界面即可,也就是之前文章中所提到的Demo。

重构目录

在这里,为了目录结构的清晰,我们简单重构一下我们的项目目录。重构后如下:

  • 我们新建了一个Sources文件夹用于保存所有的QT源文件,在Sources下,FormsHeaders分别存放UI文件和.h头文件,所有的cpp源文件直接放在Sources目录下,这里在新建好文件夹之后,只需要把main.cpp直接拖拽到Sources下即可,clion 会自动帮我们处理cmake文件中路径的问题。
  • lib目录存放我们之后需要的MQTT第三方库的 .dll文件和.a文件
  • include目录存放第三方库的头文件

新建界面UI类

对着左侧项目根目录右键,选择新建,新建一个QT Ui类:

 然后给新建的UI类起一个名字,这里就叫做MainWindow,基类我们选择Qwidget,此时我们可以看到,clion 会自动帮我们把新生成的文件添加到cmake中:

 最后我们自己把对应的文件拖拽到对应的目录中即可:

在cmake中添加头文件目录

这时候我们修改了头文件的目录,所以CMake是无法自动寻找到Headers目录的,需要我们手动指定,在cmake中添加如下内容:

1 include_directories(
2         ${PROJECT_SOURCE_DIR}/include
3         ${PROJECT_SOURCE_DIR}/Sources/Headers
4 )

修改mainwindow.cpp

此时我们直接编译会报错,所以需要自己修改一下mainwindow.cpp,将最上方头文件的引入的地址进行修改:

这里需要说明的是,QT会把UI文件预处理成对应的.h文件,然后在CPP文件中引用,生成的.h文件与UI文件同目录,所以我们想要引用的话需要正确设置文件的位置,正如上面所说一样,UI文件都在Forms目录下,所以我们引入的时候也需要指定Forms目录

这时候编译,就可以看到原来报错找不到定义或头文件的地方,都不会再报错了,因为编译过后,ui_MainWindow.h文件就会生成。

修改main.cpp

然后我们将main.cpp修改为以下内容:

 1 #include <QApplication>
 2 #include "mainwindow.h"
 3 
 4 int main (int argc, char *argv[])
 5 {
 6   QApplication a (argc, argv);
 7   MainWindow w;
 8   w.show ();
 9   return QApplication::exec ();
10 }

编译运行,就能看到我们的结果啦:

在clion 中添加外部工具

在设置中的外部工具中,添加一个新的外部工具,指向designer.exe

 然后我们就能对着UI文件右键,选择外部工具,最后使用QtDesigner打开它:

添加MQTT库

我们的demo是基于MQTT通信的,所以我们要添加一个第三方的动态库,也就是第三方的MQTT库。

添加文件

首先确保我们的工程目录结构如下:

 然后在lib目录中添加MQTT库:

 在include目录中添加头文件:

修改cmake

打开cmake文件,我们需要进行如下修改:

首先在 find_package中添加Network模块:

 然后添加第三方库文件目录:

 最后在target_link_libraries链接Network模块和MQTT库:

 完整的cmake文件如下:

 1 cmake_minimum_required(VERSION 3.21)
 2 project(QtWindowsHost)
 3 set(CMAKE_CXX_STANDARD 14)
 4 set(CMAKE_AUTOMOC ON)
 5 set(CMAKE_AUTORCC ON)
 6 set(CMAKE_AUTOUIC ON)
 7 set(CMAKE_PREFIX_PATH C:/Qt/5.14.2/mingw73_64)
 8 include_directories(
 9         ${PROJECT_SOURCE_DIR}/include
10         ${PROJECT_SOURCE_DIR}/Sources/Headers
11 )
12 find_package(Qt5 COMPONENTS
13         Core
14         Gui
15         Widgets
16         Network
17         REQUIRED)
18 link_directories(./lib)
19 add_executable(QtWindowsHost
20         Sources/main.cpp
21         Sources/mainwindow.cpp Sources/Headers/mainwindow.h Sources/Forms/mainwindow.ui)
22 target_link_libraries(QtWindowsHost
23         Qt5::Core
24         Qt5::Gui
25         Qt5::Widgets
26         Qt5::Network
27         Qt5Qmqtt
28         )

设计界面和逻辑

界面设计和逻辑就不多说了,直接上代码,UI文件可以使用TXT、Vscode等工具打开,然后就能复制粘贴了。

mainwindow.ui

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <ui version="4.0">
  3  <class>MainWindow</class>
  4  <widget class="QWidget" name="MainWindow">
  5   <property name="geometry">
  6    <rect>
  7     <x>0</x>
  8     <y>0</y>
  9     <width>452</width>
 10     <height>384</height>
 11    </rect>
 12   </property>
 13   <property name="windowTitle">
 14    <string>MainWindow</string>
 15   </property>
 16   <layout class="QGridLayout" name="gridLayout">
 17    <item row="0" column="0">
 18     <layout class="QVBoxLayout" name="verticalLayout_3">
 19      <item>
 20       <layout class="QHBoxLayout" name="horizontalLayout_5">
 21        <item>
 22         <widget class="QRadioButton" name="rb_status">
 23          <property name="text">
 24           <string>连接状态</string>
 25          </property>
 26         </widget>
 27        </item>
 28        <item>
 29         <widget class="QPushButton" name="pb_connect">
 30          <property name="text">
 31           <string>Connect</string>
 32          </property>
 33         </widget>
 34        </item>
 35       </layout>
 36      </item>
 37      <item>
 38       <layout class="QHBoxLayout" name="horizontalLayout_3">
 39        <item>
 40         <layout class="QVBoxLayout" name="verticalLayout">
 41          <item>
 42           <layout class="QHBoxLayout" name="horizontalLayout">
 43            <item>
 44             <widget class="QLabel" name="label">
 45              <property name="text">
 46               <string>Topic:</string>
 47              </property>
 48             </widget>
 49            </item>
 50            <item>
 51             <widget class="QLineEdit" name="le_pb_topic"/>
 52            </item>
 53           </layout>
 54          </item>
 55          <item>
 56           <layout class="QHBoxLayout" name="horizontalLayout_2">
 57            <item>
 58             <widget class="QLabel" name="label_2">
 59              <property name="text">
 60               <string>Payload:</string>
 61              </property>
 62             </widget>
 63            </item>
 64            <item>
 65             <widget class="QLineEdit" name="le_pu_payload"/>
 66            </item>
 67           </layout>
 68          </item>
 69         </layout>
 70        </item>
 71        <item>
 72         <widget class="QPushButton" name="pushButton">
 73          <property name="text">
 74           <string>Publish</string>
 75          </property>
 76         </widget>
 77        </item>
 78       </layout>
 79      </item>
 80      <item>
 81       <layout class="QHBoxLayout" name="horizontalLayout_4">
 82        <item>
 83         <widget class="QLabel" name="label_3">
 84          <property name="text">
 85           <string>Topic:</string>
 86          </property>
 87         </widget>
 88        </item>
 89        <item>
 90         <widget class="QLineEdit" name="le_sub_topic"/>
 91        </item>
 92        <item>
 93         <widget class="QPushButton" name="pushButton_2">
 94          <property name="text">
 95           <string>Subscribe</string>
 96          </property>
 97         </widget>
 98        </item>
 99        <item>
100         <widget class="QPushButton" name="pushButton_3">
101          <property name="text">
102           <string>UnSubscribe</string>
103          </property>
104         </widget>
105        </item>
106       </layout>
107      </item>
108      <item>
109       <layout class="QVBoxLayout" name="verticalLayout_2">
110        <item>
111         <widget class="QLabel" name="label_4">
112          <property name="text">
113           <string>LOG:</string>
114          </property>
115         </widget>
116        </item>
117        <item>
118         <widget class="QTextBrowser" name="te_log"/>
119        </item>
120       </layout>
121      </item>
122     </layout>
123    </item>
124   </layout>
125  </widget>
126  <layoutdefault spacing="6" margin="11"/>
127  <resources/>
128  <connections/>
129 </ui>

mainwindow.h

 1 //
 2 // Created by XinMouRen on 2022/1/25.
 3 //
 4 
 5 #ifndef _MAINWINDOW_H_
 6 #define _MAINWINDOW_H_
 7 
 8 #include <QWidget>
 9 #include "qmqtt.h"
10 QT_BEGIN_NAMESPACE
11 namespace Ui
12 {
13 class MainWindow;
14 }
15 QT_END_NAMESPACE
16 
17 class MainWindow : public QWidget {
18  Q_OBJECT
19 
20  public:
21   explicit MainWindow (QWidget *parent = nullptr);
22   ~MainWindow () override;
23   QMQTT::Client *client;
24   void on_pb_connect_clicked();
25   void on_pushButton_clicked();
26   void on_pushButton_2_clicked();
27   void on_pushButton_3_clicked();
28   void doConnected();  //MQTT 连接成功
29   void doDisconnected();//MQTT连接断开
30   void doDataReceived(QMQTT::Message);//MQTT收到数据
31  private:
32   Ui::MainWindow *ui;
33 };
34 
35 #endif //_MAINWINDOW_H_

mainwindow.cpp

  1 //
  2 // Created by XinMouRen on 2022/1/25.
  3 //
  4 
  5 // You may need to build the project (run Qt uic code generator) to get "ui_MainWindow.h" resolved
  6 
  7 #include "Headers/mainwindow.h"
  8 //  #include "ui_MainWindow.h"    这是原来的
  9 #include "Forms/ui_MainWindow.h"
 10 
 11 MainWindow::MainWindow (QWidget *parent) :
 12     QWidget (parent), ui (new Ui::MainWindow)
 13 {
 14   ui->setupUi (this);
 15   client = new QMQTT::Client ();
 16   client->setHostName ("127.0.0.1");
 17   client->setPort (1883);
 18   client->setClientId ("clientid");
 19   client->setUsername ("user");
 20   client->setPassword ("password");
 21   ui->pushButton->setEnabled (false);
 22   ui->pushButton_2->setEnabled (false);
 23   connect (this->client, &QMQTT::Client::connected, this, &MainWindow::doConnected);
 24   connect (this->client, &QMQTT::Client::disconnected, this, &MainWindow::doDisconnected);
 25   connect (this->client, &QMQTT::Client::received, this, &MainWindow::doDataReceived);
 26 }
 27 void MainWindow::on_pb_connect_clicked ()
 28 {
 29 
 30   if (!client->isConnectedToHost ())
 31     {
 32       client->connectToHost ();
 33     }
 34   else
 35     {
 36       client->disconnectFromHost ();
 37     }
 38 
 39 }
 40 
 41 void MainWindow::doConnected ()
 42 {
 43   ui->rb_status->setChecked (true);
 44   ui->pb_connect->setText ("Disconnect");
 45   ui->pushButton->setEnabled (true);
 46   ui->pushButton_2->setEnabled (true);
 47 }
 48 
 49 void MainWindow::doDisconnected ()
 50 {
 51   ui->rb_status->setChecked (false);
 52   ui->pb_connect->setText ("Connect");
 53   ui->pushButton->setEnabled (false);
 54   ui->pushButton_2->setEnabled (false);
 55 }
 56 
 57 void MainWindow::doDataReceived (const QMQTT::Message &message)
 58 {
 59   QString mes =
 60       QString (message.id ()) + " " + QString (message.qos ()) + " " + message.topic () + " " + message.payload ()
 61       + "\n";
 62   ui->te_log->append (mes);
 63 }
 64 
 65 void MainWindow::on_pushButton_clicked ()
 66 {
 67   QString topic = ui->le_pb_topic->text ().trimmed ();
 68   QString payload = ui->le_pu_payload->text ().trimmed ();
 69   if (topic.isEmpty () || payload.isEmpty ())
 70     {
 71       qDebug () << "pub topic and payload is empty!";
 72       return;
 73     }
 74   QMQTT::Message message (136, topic, payload.toUtf8 ());
 75 
 76   client->publish (message);
 77 }
 78 
 79 void MainWindow::on_pushButton_2_clicked ()
 80 {
 81   QString topic = ui->le_sub_topic->text ().trimmed ();
 82   if (topic.isEmpty ())
 83     {
 84       qDebug () << "sub topic and payload is empty!";
 85       return;
 86     }
 87   qDebug () << topic;
 88   client->subscribe (topic);
 89 }
 90 
 91 void MainWindow::on_pushButton_3_clicked ()
 92 {
 93   QString topic = ui->le_sub_topic->text ().trimmed ();
 94   if (topic.isEmpty ())
 95     {
 96       qDebug () << "sub topic and payload is empty!";
 97       return;
 98     }
 99   client->unsubscribe (topic);
100 
101 }
102 
103 MainWindow::~MainWindow ()
104 {
105   delete ui;
106 }

运行

将上述代码编译运行后,可以看到如下界面:

 经测试,我们的MQTT通信也是正常的。

posted on 2023-08-10 14:14  一杯清酒邀明月  阅读(681)  评论(0编辑  收藏  举报