一、main.cpp
- QApplication
- 首先代码映入眼帘的就是
QApplication app(argc, argv)
,这句是QApplication管理GUI程序的控制流和主要设置,QApplication包含窗口系统和其他来源处理过和发送过的主事件循环。它也处理应用程序的初始化和收尾工作,并提供对话管理。QApplication可以对系统和应用的大部分设置项进行设置。 - 对于用Qt写的任何一个GUI应用,不管这个应用有没有窗口或多少个窗口,有且只有一个
QApplication对象
。 - 而对于用Qt写的非GUI应用,则有且只有一个
QCoreApplication
对象,并且这个应用不依赖QtGui库
。
这个QApplication对象的指针可以通过instance()函数
获取,它和一个全局指针qApp
等价。
QApplication
的主要功能是:
功能 | 描述 |
---|---|
使用所在桌面的参数 | 调色板(palette()) 、字体(font()) 、双击间隔(doubleClickInterval()) 等信息初始化应用程序。当我们改变桌面的一些设置时,可以让应用程序的这些设置保持一致。 |
从底层窗口系统接收事件 | 并通过sendEvent() 或postEvent() 发送给需要的窗口。 |
通过解析命令行参数 | 来设置程序内部状态 |
改变应用程序的外观 | 在运行时,可以通过setStyle()函数 来改变QApplication 包含的一个QStyle 对象。 |
制定程序的颜色策略 | 详见setColorSpec()函数 说明。 |
设置本地化的字符串 | 通过translate()函数 |
还包含一些非常方便的类 | 例如屏幕信息类(desktop()) 和剪切板类(clipboard()) |
包含所有窗口的信息 | 可以知道程序在屏幕上的位置(widgetAt()) ,顶层窗口列表(topLevelWidgets()) ,关闭所有窗口(closeAllWindows()) 等等 |
能够管理鼠标光标样式 | 参照setOverrideCursor() |
提供刷新和同步通讯流的函数 | 参看flushX() 和 syncX() |
提供全面的与用户交互界面 | 当用户注销时,可以正常关闭;如果不能终止程序,它能取消关机进程;甚至可以保存程序全部状态。参看 isSessionRestored() ,sessionId() and commitData() and saveState() |
-既然QApplication做了这么多初始化工作,因此它必须在创建其他与用户界面相关的类之前创建。QApplication能够处理命令行参数,所以在想要处理命令行参数之前就要创建它。
头文件 | 继承于 |
---|---|
#include | QCoreApplication |
- <ros_qt>
::MainWindow
第二句就是ros_qt::MainWindow w(argc, argv)
,首先解释一下<ros_qt>
,这是自己定义的一个命名空间(当然ros_qt的定义放在了头文件中了),如图所示:
其中w(argc, argv)
就是创建了一个界面对象。
之后三句:
w.show(); //使用了`.show()`方法才能显示QT界面
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); //使用`connect()`槽函数作用是获取到关闭窗口信号后处理上一个窗口的关闭,确保所有窗口都能正常退出。
int result = app.exec(); //使用`.exec()`方法来确保程序在不断循环,直到关闭窗口
- 总结: main函数写法都比较简洁,主要作用是规定窗口对象及其属性以及让QT窗口能保持直到点击关闭或者退出。
二、qnode
qnode在ROS交互界面开发起到了非常重要的作用,使用qnode提前设好的规则可以更快速更方便地进行节点的:初始化、定义、属性修改、log日志记录设定。首先来看一下qnode.h如何编写:
1 /*****************************************************************************
2 ** Ifdefs
3 *****************************************************************************/
4
5 #ifndef ros_qt_QNODE_HPP_
6 #define ros_qt_QNODE_HPP_
7
8 /*****************************************************************************
9 ** Includes
10 *****************************************************************************/
11 #include <ros/ros.h>
13 #include <string>
14 #include <std_msgs/Float64.h>
15 #include <std_msgs/Int32.h>
16 #include <QThread>
17 #include <QStringListModel>
18 #include <cv_bridge/cv_bridge.h>
19 #include <image_transport/image_transport.h>
20 #include <sensor_msgs/image_encodings.h>
21 #include <sensor_msgs/Image.h>
22 #include <geometry_msgs/Twist.h>
23
24 #include <opencv2/opencv.hpp>
25 #include <QImage>
26
27 /*****************************************************************************
28 ** 自定义信号参数类型
29 *****************************************************************************/
30
31
32 /*****************************************************************************
33 ** Namespaces
34 *****************************************************************************/
35
36 namespace ros_qt {
37
38 /*****************************************************************************
39 ** Class
40 *****************************************************************************/
41
42 class QNode : public QThread {
43 Q_OBJECT
44 public:
45 QNode(int argc, char** argv );
46 virtual ~QNode();
47 bool init();
48 bool init(const std::string &master_url, const std::string &host_url);
49 void run();
50 void myCallback(const std_msgs::Float64& message_holder);
51 void Comp_videoCallback(const sensor_msgs::CompressedImageConstPtr& msg);
52 void Image_videoCallback(const sensor_msgs::Image& msg);
53 void sound_SensorCallback_F(const std_msgs::Int32& msg);
54 void sound_SensorCallback_R(const std_msgs::Int32& msg);
55 void speed_Callback_L(const std_msgs::Int32& msg);
56 void speed_Callback_R(const std_msgs::Int32& msg);
57 void angle_Callback_X(const std_msgs::Int32& msg);
58 void angle_Callback_Y(const std_msgs::Int32& msg);
59 void lidarDistance_Callback(const std_msgs::Int32& msg);
60 void odomeData_Callback(const std_msgs::Int32& msg);
61 void move_base(char k, float speed_linear, float speed_trun);
62
63 /*********************
64 ** Logging
65 **********************/
66 enum LogLevel {
67 Debug,
68 Info,
69 Warn,
70 Error,
71 Fatal
72 };
73
74 QStringListModel* loggingModel() { return &logging_model; }
75 void log_Float64( const LogLevel &level, const std_msgs::Float64 &msg);
76 void log_Int32( const LogLevel &level, const std_msgs::Int32 &msg);
77
78 Q_SIGNALS:
79 void loggingUpdated();
80 void rosShutdown();
81 void Show_image(QImage);
82 void Show_soundSensor_F(qint32);
83 void Show_soundSensor_R(qint32);
84 void Show_speedData_L(qint32);
85 void Show_speedData_R(qint32);
86 void Show_angleData_X(qint32);
87 void Show_angleData_Y(qint32);
88 void Show_lidarDistance(qint32);
89 void Show_odomeData(qint32);
90
91 private:
92 int init_argc;
93 char** init_argv;
94 /************* Subscriber ********************/
95 ros::Subscriber chatter_subscriber;
96 ros::Subscriber video_subscriber;
97 ros::Subscriber sound_subscriber_F;
98 ros::Subscriber sound_subscriber_R;
99 ros::Subscriber speed_subscriber_L;
100 ros::Subscriber speed_subscriber_R;
101 ros::Subscriber angle_subscriber_X;
102 ros::Subscriber angle_subscriber_Y;
103 ros::Subscriber lidarDistance_subscriber;
104 ros::Subscriber odomeData_subscriber;
105
106 /************* Publisher ********************/
107 ros::Publisher cmd_pub;
108
109 QStringListModel logging_model;
110 QImage Mat2QImage(cv::Mat const &src);
111 };
112
113 } // namespace ros_qt
114
115 #endif /* ros_qt_QNODE_HPP_ */
解析:
-
在qnode.h头文件中添加自定义回调函数定义,如图所示:
-
添加自定义QT信号函数,如图所示:
-
添加自定义ROS节点接收话题对象,如图所示:
-
添加自定义ROS节点发布话题对象,如图所示:
-
总结:qnode.h主要是定义了节点初始化、属性、回调函数、信号函数、发布话题对象、接收话题对象,主类名为QNode派生于QTheard,以后需要添加自定义的节点、信号只需要在对应部分添加定义即可。
Tips:固然qnode.h实现于qnode.cpp
三、ROS-QT界面设计
前面小节讲了QT程序的基本定义和使用以及如何添加qnode的节点定义、信号、发布、订阅,接下来讲解如何设计ROS的QT界面并使用。
1、使用Qt Designer设计界面
安装了QT后可以使用Qt Designer的自带控件进行界面绘制,并在编译运行后自动生成main_window.ui文件和ui_main_window.h文件。
打开Qt Designer后如图所示,使用左侧自带控件即可绘制ui界面,创建的时候尽量取好窗口名,防止后续编程乱套:
在绘制ui界面的时候可以根据右侧的属性编辑器对控件进行修改,包括尺寸、标题、派生对象、文字格式等等。
绘制完成后,需要记住自己控件的名字,方便以后编程使用,如果不记得自己的控件名了,可以在对象查看器选中后在属性编辑器上查看,如图所示:
2、加入QT ui到ROS功能包
绘制完成并运行后会生成两个文件,一个三ui_main_window.h,一个是main_window.ui,需要将这两个文件添加到ROS功能包中:
# 进入功能包
cd <功能包名字>
# 创建ui目录
mkdir ui
# 拷贝ui文件到ui目录中
cp <main_window.ui文件路径> ui
# 拷贝ui_main_window.h到头文件目录
cp <ui_main_window.h头文件目录> include
放置完成后如图所示:
其中resources就是放ui设计的时候使用的图片等需要一些加载的源文件,如果没有就可以不用添加。
3、实现控件功能
设计好界面ui后,就需要根据自己的ui_main_window.h实现控件的功能,在src中添加main_window.cpp实现功能。