Qt话题(更新)

一、基础(待续)


我想:“你一定会长成健康的胖子”。虽然是胖子但你很敏捷,让加载更快吧。让胖子飞起来吧~~。
不喜欢在vs里通过插件的方式使用qt,creator的调试功能足够了。

资源

官方安装包下载链接,6.0以上需要源码编译或在线安装

项目文件

pro文件

  1. 想知道配置项的内容是什么?简单的message($$CONFIG)就可以搞定。输出的信息展示在"6.摘要信息"中。
  2. 平台依赖的代码怎么定义呢?看看下面的内容,显然不难。
unix{
DEFINES += PLATFORM_LINUX
}
win32{
LIBS += -lws2_32
DEFINES += PLATFORM_WIN32
}
  1. LIBS的用处,一是精确定义依赖库的位置和名称;二是通知调试器依赖库的查找位置。第二点可以有效解决creator调试时无法启动目标软件的问题。
LIBS += -Lyour_libs_path

pri文件

字符和数字

UTF-8,UTF-16,ANSI等字符编码,你就使劲的玩儿吧。
QString 是UTF-16编码,从16bit字符转到8bit字符转换,Qt提供三种方法:

QString str("hello qt world");
QByteArray byte1 = str.toUtf8();   //utf-8编码的8bit字符,utf-8是US-ASCII (ANSI X3.4-1986)的超集
QByteArray byte2 = str.toLatin1();     //拉丁文8bit字符
QByteArray byte3 = str.toLocal8Bit();  //本地系统默认8字符

序/反列化

文件读写是非常基础的技术,在数据序/反列化中,需要特别强调的是:自定义格式中的版本兼容问题。QDataStream支持许多QT原生类型的序列化与反序列化,不的不说这个类方便耐用。
以下是我对官方文档中关于使用QDataStream类进行数据序列化和反序列化的理解。

  1. 自定义文件格式的头部至少应设计为包括magic_number + version两部分信息。看代码
  2. magic_number用于确定文件格式是否正确。
  3. version用于确定使用那部分代码读取数据。
  4. QDataStream要求待序列化数据为强类型&必须是它支持的类型
//序列化内存数据到文件
QDataStream out(&file);
out<<(quint32)0x0A0B0C0D;
out<<(qint32)123;
out.setVersion(Qt_4_0);
out<<some_intresting_data;

//反序列化文件到内存数据
QDataStream in(&file);
quint32 magicNum;
in>>magicNum;
if (0x0A0B0C0D != magicNum) {
	return BAD_FILE_FORMAT;
}
qint32 version;
in>>version;
if (version < 100) {
	in.setVersion(Qt_3_2);
else
	in.setVersion(Qt_4_0);
}
in>>some_instresting_data;

信号与槽

N种款式,你喜欢啥?

  1. 传统型内部的较量
connect(sender, SIGNAL(signal_fun(QObject*)), this, SLOT(slot_fun(QObject*)));
connect(sender, SIGNAL(signal_fun(QObject*)), this, SLOT(slot_fun()));
connect(sender, SIGNAL(signal_fun()), this, SLOT(slot_fun()));
  1. 信号无参数,槽有参数,传统找死型
connect(sender, SIGNAL(signal_fun()), this, SLOT(slot_fun(QObject*)));
  1. 函数指针,简约型
QObject::connect(&objectA, &QObject::signal_fun, &objectB, &QObject::slotFun);
  1. lambda表达式,高级简约型
    关注两点:lambda表达式1,QObject::sender()2
connect(action, &QAction::triggered, engine,
         [=]() { engine->processAction(action->text()); }); 

可能的错误1:QMetaObject::connectSlotsByName: No matching signal for
原因:槽函数使用了“on_控件名_信号名”的格式。
解决办法:修改槽函数为非“on_控件名_信号名”的格式的名称。

总结:首选高级和简约型,5.0之前的版本另讲。

界面也要礼尚往来

  1. 创建一个全局单例对象,用于管理不同层次界面间的必要信号&槽链接。

退出应用的函数

事件循环是Qt的重要概念,与事件循环有密切关系的退出函数值得一提。这些细节就是生产环节必不可少的内容。

QCoreApplication::quit();
QCoreApplication::exit(0);

上面的两个函数会导致应用退出,不过也有例外。比如说:没有进入事件循环前,对他们的调用将没有任何效果。一个好的编码实践是(看看有下面的代码和你的代码有什么不同,然后我认为Qt的文档是业界最牛逼的-简单、明了,结构清晰,节约生命。):

QPushButton *quitButton = new QPushButton("Quit");
connect(quitButton, SIGNAL(clicked()), &app, SLOT(quit()), Qt::QueuedConnection);

事件循环

看几个问题:

  1. 谁开启了事件循环?
  2. 谁又导致事件循环退出?
  3. 事件循环的空闲时间怎么利用?
  4. 怎么适时释放动态资源?

关于问题的答案:

  1. 是它开启了应用程序的事件循环,似乎已经熟悉到忽略他的存在了。
return QCoreApplication::exec();
  1. 主动调用退出应用的函数,或者关闭了窗口。退出应用的函数文中已有介绍,不再赘述。需要多说的是,exec()是主函数的最后一句代码,动态资源释放将变的非常尴尬++(释放代码也希望在主函数最后)。Qt考虑了很多。Qt推荐:把释放资源的槽函数连接到aboutToQuit()信号,是非常好的编码实践。这个信号在退出事件循环后触发,同时,作为私有信号它不能被人为emit,感觉吧啦吧啦说到现在,终于可以安静的休息了。
  2. 事件循环由exec()接管,看似无法插手,但Qt考虑了很多,此时使用QTimer或者QCoreApplication::processEvents()是不二选择。比较形象的词是:狼嘴里抢肉就靠它两。
  3. 下面的一句话足以解决心中烦闷。
QObject::conncet(this, &QCoreApplication::aboutToQuit, this, &cleanUp);

还有要说的


如果想使用第三方信号槽机制,这句话丢到pro的肚子里。两方机制都想使用,把源码中的信号和槽用QT特有宏包裹起来吧,Q_SIGNALS/Q_SIGNAL,Q_SLOTS/Q_SLOT。

CONFIG += no_keywords

日期和时间

直奔主题,这两天在搞基于Linux的嵌入式设备代码,遇到一个时间同步的(上位机的时间同步到设备)问题。借此机会,把过程梳理一遍。
背景:设备接收上位机派发的任务,并在规定的时间开始执行任务。这个简单的需求中,需要考虑设备与上位机的时间的一致性问题。
我的实现方式是:上位机下发以UTC为标准的时间戳,设备把时间戳还原为具体时间。按理说很简单,不是吗?但是出问题了,经过调试发现,设备侧无法还原出与上位机一致的时间。导致设备不能按照要求准时执行任务。问题在哪里?
经过一番折腾,发现“时区”差异导致了时间还原不正确的问题。既然是时区问题,那么答案就简单了。如果通信双方都是通用计算机,建议设置时区,这样再简单不过。我的环境刚好是嵌入式设备,那么我的需要其他有效的方式。下面是我的代码:

//上位机测试代码
QDateTime localTime = QDateTime::currentDateTime();
QDateTime utcTime = localTime.toUTC();
quint64 secSinceE = utcTime.addSecs(localTime.offsetFromUtc()).toTime_T();

//下位机
printf("%s", asctime(localtime(secSinceE)));

重点说明的内容,localTime.toUTC()是含有时区概念的时间,这个时间需要调整,调整的量由offsetFromUtc()的结果决定。因为我是东半球,北京时间,所以win10系统下通过Qt的QDateTime产生的UTC时间与绝对UTC相差28800秒,也就是8小时。把8小时补回来,设备能容易的还原时间。
方法总结:
方法1.让通信双方的时区保持一致;
方法2.向设备的默认时区妥协,由上位机产生可还原时间戳。我使用的方法。
以上代码的前提条件:我的设备侧默认是绝对UTC,也就是UTC+0000。你的情况或许是另外一番景象,但是坚持方法总结中的第一条,不会走偏。

单元测试

在编码实践中,无论你是否老辣,单元测试应成为咱的守护天使。节约时间就是节省生命资源。单元测试框架我只用过googletest。这次项目中使用Qt原生的单元测试框架:QTest。除自身的测试框架外,Qt也非常好的支持googletest。本节只说QTest。

要素

  1. 独立的测试项目(不侵入待测试项目的源代码):新建项目中选择其他项目后,可以顺利的找到测试项目;
  2. 添加待测项目源文件目录到测试项目中,体现在pro的SOURCES和INCLUDES;
  3. 测试自定义类,为了访问类中的私有成员,请添加==#define private public==到测试文件尽量靠前的位置(见下);
#include <QTest>
#define private public

#include <your_source_header1>
#include <your_source_header2>

class autotest_uint
{
...
private slots:
void autotest_case1_fun();
}

void autotest_unit::autotest_case1_fun()
{
CYourClass test;
test.load(your_data_file);
QVERIFY(test.isOk());
QCOMPARE(test.mSize, 5);
}

数据驱动的测试

外围代码见要素,只看重点。
test_case2_bydata_data()3
test_case2_bydata()4

autotest::test_case2_bydata_data()
{
	QTest::addColumns<QString>(your_define_test_data);
	QTest::addColumns<qint32>(you_define_expect_value);
	QTest::newRow("test_data_1")<<"aaaa"<<4;
	QTest::newRow("test_data_2")<<""<<0;
}
autotest::test_case2_bydata()
{
QFETCH(QString, data);
QFETCH(qint32, value);
QCOMPARE(data.size(), value);
}
//test_case2_bydata_data() //组织测试数据
//test_case2_bydata() //测试用例

日志系统


QT日志定义

  1. qInstallMessageHandler(fun_pointer),qt开放给用户的日志信息方法,很周到。qInstallMessageHandler(0)可以告诉我们fun_pointer。
  2. 致命信息(QtFatalMsg)会导致应用立即退出。
  3. 日志应有的小弟:包括时间,等级、所在文件、所在行号、描述信息等。
  4. debug和release的日志都要输出?pro文件中增加
DEFINES += QT_MESSAGELOGCONTEXT

关闭日志输出

关闭日志输出注意两点,不然你会郁闷。关闭日志在QTest中特别给力。

  1. 在profile文件中增加一下内容,自由搭配,适合项目就好。
  2. 一定要重新构建
DEFINES += QT_NO_WARNING_OUTPUT \
            QT_NO_DEBUG_OUTPUT \
            QT_NO_INFO_OUTPUT

本地化

应用打包


打包相关的章节,《坑坑哇哇》->“打包程序”。

必要的库文件

发布软件包时,考虑以下库文件的复制。笨人笨办法:

  1. 查看pro文件中的QT定义,请复制对应库到可执行文件位置。例如:
QT += gui network sql

此时最少需要从编译工具链对应的bin目录(C:\Qt\Qt5.12.9\5.12.9\mingw73_64\bin这是我的文件位置)下获取Qt5Gui.dll,Qt5Network.dll, Qt5Sql.dll文件,然后复制到待发布软件包目录。

  1. 查看pro文件中的LIBS定义,第三方的库文件同样需要亲自处理,复制到待发布软件包目录。
  2. plugins下的platforms目录(C:\Qt\Qt5.12.9\5.12.9\mingw73_64\plugins\platforms==我的文件位置)复制到待发布软件包目录。平台依赖库
    除plugins中的库文件外,其他库文件应放置在可执行文件同级目录。

二、进阶(待续)

状态机

视图模型

listview

它的模型之一:QStringListModel,QStringList内容的改变自动反馈到View,这就是MVC中的MV。例子:滚动展示日志的精要。

QStringList msgList;
msgList<<"有新的TCP连接请求";
msgList<<"设备磁盘占用超过80%";

QStringListModel *msgListModel = new QStringListModel;
msgListModel->setStringList(msgList);

listView->setModel(msgListModel);

void onMsgReady(QString logMsg)
{
	QStringList msgList = listView->model().stringList();
	msgList<<logMsg;
	listView->model().setStringList(msgList);
}

定时器

通信

内部进程通信

仍不住的想说:QT的文档建档,简单明了,爱了。剩下的只需要知道关键字,然后就能办了问题。比如说这个主题《内部进程通信》。在帮助文档中通过索引的方式,搜索“inter-process”,一切真相大白。
这个话题放在这里有一段时间了,今天在嵌入式Linux中调试Qt5.6编写的IPC代码。背景:原有框架中已指定IPC的方式:AF_UNIX的内部通信机制。先加入新功能,仍以进程方式协作。为了提高开发效率,新加入的功能使用Qt5.6开发。按理说QLocalSocket可以很好的解决通信问题,结果是乌龙百出。
问题出在:QLocalSocket的具名连接方法()上。看上去,它的使用很简单,其实这里有个“具名”路径问题,否则会出现无法连接服务端的问题。
原有代码的“具名”路径是可执行文件的同级目录,连接方法默认的“具名”路径是一个犄角旮旯的地方,只有同时使用Qt开发C/S两端时不会出问题,除此以外很难建立连接关系。
你知道吗?当涉及文件时,路径是必须考虑的要素。而linux下一切皆文件,那么今后谈文件,就应该问路径,否则弯路是要走一些的。最终的关键代码如下:

QString serverName = QCoreApplication::applicationDirPath();
serverName += "/your_ipc_name";
QLocalSocket ipcSocket;
ipcSocket.connectToServer(serverName);
if (ipcSocket.waitForConnection()) {
	//hardwork.
}

网络通信

QTimer

毫秒级的高级别定时器,用于非精度定时场合。其实这个定时的精度是可配置的,定时器分为3个级别,毫秒,偏差5%毫秒和秒。

  1. 默认偏差5%毫秒示例
#include <QTimer>

QTimer *timer = new QTimer();
timer->setInterval(1000); //<<这里是毫秒
timer->connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()));
timer->start();
  1. 毫秒精度示例
#include <QTimer>

QTimer *timer = new QTimter();
timer->setTimerType(Qt::PreciseTimer);
timer->start(50); //是的,50毫秒定时器为你工作了。
  1. 秒级精度的代码不想写了。我认为QT的开发文档绝对是最牛的,应该颁发最佳责任奖。不但表达清晰而且示例结合超级好。

多线程

多线程也是双刃剑,如果不能很好的控制和理解,我想还是老老实实的在单个线程中干活吧(简单,省心)。如果单线程真的不能满足你的任务需求,也还是要绞尽脑汁的想出:为什么必须用多线程。
如果必须使用多线程处理你的业务,了解QT下的使用多线程思路是必要:
考虑一下这个问题

  1. 业务线程中是否使用信号槽?
    可能的情况:
    1.我的业务就是一个while(true) {do something}搞定,纯粹的使用CPU算力。
    2.需要借助Qt自身的事件机制,分状态的处理业务。
    我的看法:
    “可能的情况”中描述了问题的解答思路,情况1是说:业务中不使用Qt的信号与槽核心机制,所有的事件由开发人员自行处理,相当与写一个专用与自身业务的事件处理机制。优点是可控性强,缺点是代码量大,且不能使用信号槽任何便捷。
    情况2是说:我要像GUI线程一样,充分使用Qt框架提供的便捷,少操心就好。这是需要真正理解线程中的事件循环,退出和阻塞等要点。exec(),exit(),wait()是需要关注的内容。优点是Qt为我们考虑的所有机制都可以使用,省心省力。缺点是需要深入了解Qt的机制。
    我倾向于情况2,以上是近期做任务的领悟。

并发

  1. 转移线程,moveToThread();

连接的艺术

  1. 自动连接是什么,它负责解决什么问题。Qt::AutoConnection;
  2. 直连是什么,它又负责解决什么问题。QT::DirectConnection;
  3. 为什么提供查询类的连接,Qt::QueuedConnection;
  4. 阻塞连接复杂吗?解决什么问题?Qt::BlockingQueuedConnection;
  5. 唯一连接难懂吗?又要解决什么问题?Qt::UniqueConnection。

绘图

反走样(抗锯齿)

在graphicview及其子类里提供反走样函数,绘制的图形更平滑,这种魅力是牺牲cpu时间换来的。下面代码不要放错位置。

your_view_object.setRenderHint(QPainter::Antialiasing);

QElapsedTimer


计算已消耗时间的便捷类。它提供的start和elapsed是高频方法。要重新计时只需要再次调用start方法就好。

QDeadlineTimer


三、win下编译Qt6

重要的参考资料

  1. 官方编译指导
  2. 配置参考

先看生成命令

关键的几条命令可以解决编译和安装问题。当然,一定有后话。
启动x64 native tool command type for vs2019环境,使用一下命令。

cd qt_source_dir
configure -debug -prefix setup_path -opensource -- -Bbuild_path
cmake --build . -parallel
cd build_path
ninja install

我的编译命令,供参考
没有包括examples的编译命令如下:

configure -release -prefix d:/qt6 -opensource -- -B../build/release -DCMAKE_PREFIX_PATH=e:/llvm/  -DFEATURE_clangcpp=ON
cd ../build/release/
ninja
ninja install

包括examples的编译命令如下:

configure -release -prefix d:/qt6 -make examples -qt-zlib -qt-libjpeg -qt-libpng -qt-freetype -qt-pcre -qt-harfbuzz -opensource -- -Be:/qt/build/release -DQT_NO_MAKE_EXAMPLES=ON -DCMAKE_PREFIX_PATH=e:/llvm/ -DFEATURE_clangcpp=ON
cd ../build/release/
ninja
ninja install

其他配置见"重要的参考资料"一节。
llvm用于编译QDoc,生成Qt离线文档。

cd ./build/release
ninja docs
ninja install_docs
assistant -register qtdoc.qch

ninja docs执行之后,doc目下自动生成qch类型文件和qhp类型,其中qch可以通过qtcreator的帮助界面查看。
参考的资料,适用于qt5。

编译环境准备

  1. vs 2019 构建工具,不必安装IDE。类似的内容,看看ffmpeg的编译是有用的。
  2. CMake下载和安装。
  3. python 3.9以上的下载和安装。
  4. perl下载和安装。
  5. ninja下载和安装,类似于make的轻量级但高效的编译文件组件工具
  6. Qt6源码下载
  7. QtCreator5.0下载

Qt6编译成功后的第一个应用程序

经过前面的准备,编译和安装,也许晕了多圈儿了,但是问题依然存在,请再保持清晰,看完这一节再做其他打算。

  1. 使用creator5新建GUI工程,不必编写任何代码,默认的内容足矣。
  2. 在creator的工具->选项中配置kit,主要是配置Kits中的Qt version字段为已编译并安装好的Qt6。
  3. 更加重要的是系统环境变量中的TEMP中不能包括中文字符,否则编译错误将是:can open 巴拉巴拉.jom for write。

Qt6结束

其实,这是最基础组件的的编译。更进一步的编译,像额外的模块编译和configure的有大量选项,都需要时间实践和消化,慢慢来,持续补充。

四、坑坑洼洼(待续)

字符编码

乱码,QString默认编码,本地系统编码。三者搞清楚后,乱码将从源头干掉。
这篇文章值得一看

编译链接

突然接到一个任务,编译一个满是中文字符串和中文注释的基于QT creator开发的软件源代码。因为是在windows10 x64编译,我理所当然的选择了msvc 2017 x64作为编译工具链。问题因此出现了,文件编码问题引发了大量编译错误。解决办法如下:

  1. 使用其他文本编辑工具转换所有源文件为utf-8 + BOM,然后编译;我没有采用这个方法,引用自网络资料;
  2. 所有源文件增加编译选项:#pragma execution_character_set(“utf-8”),我尝试过,文件太多,一定还有更好的办法;
  3. 干脆视而不见,屏蔽告警信息。<==不能解决根本问题。
  4. 更换编译工具,我换成了MinGW x64。换了编译器躁动的世界终于安静了。多说一句:msvc存在文件编码引起的编译问题。
    没错你看到我经历了。我尝试处理所以错误,但这本身就是个错误,果断更换编译工具。

文件路径

  1. 软件运行时依赖的外部资源怎么处理?我的作法是:统一放置,然后定义全局相对路径,切记满世界硬编码路径。
QString path = QCoreApplication::applicationDirPath(); //可执行文件所在的目录
  1. QFileInfo和QDir能我很好的完成文件创建,重命名,路径创建,文件和路径分离等等能想到的文件管理功能。
//分离路径
QFileInfo fileInfo("your/path/file");
QString path = fileInfo.path();
QString fileName = fileInfo.fileName();
//创建路劲
QDir target("");
target.mkpath(path);  //创建父级所有路径,如果路径已存在则返回true.
//复制文件到新的位置
target.copy("new/path/file");

运行时异常

  1. 传入实参的合法性一定要检查,不然死的很惨。
  2. 关注占用80%运行时间的20%代码逻辑。想好了,盯紧了,测稳了。

异常捕获

调试手段

  1. 程序运行时附带控制台窗口,观察输出信息。CONFIG += console

收不到信号

在调试QLocalSocket的时候,无论如何都没有收到过connected信号(Qt5.12.9),这是怎么一回事?请同行点拨一下。

打包程序

自动化方法


在程序开发的生命周期里,把开发成果打包是无法跳过的重要步骤。今天遇到release版+基础qt库无法打包后无法运行在目标机的问题。提示:no qt platform plugins initialized。
解决方式比较简单:

  1. 确定编译工具,例如:msvc 2017 32bit这是我的编译工具。
  2. 在qt安装目录下,找到msvc 2017目录下的plugins/platforms。把整个platform文件夹复制到可执行程序相同位置。
  3. platform下的内容包括调试版和发行版动态连接库。自行处理

  1. C++11引入的特性,有搞头儿。格式:[=](参数){函数实现;} ↩︎

  2. 返回发送信号的对象指针。起飞的节奏。 ↩︎

  3. 组织测试数据的函数fun_name+_data。 ↩︎

  4. 实施测试的测试用例函数fun_name。 ↩︎

### 回答1: Qt 是一个跨平台的应用程序开发框架,ROS(机器人操作系统)是一个用于开发机器人软件的软件框架。订阅 ROS 话题是指使用 Qt 框架编写的应用程序可以获取 ROS 中发布的话题数据。 在 Qt 中订阅 ROS 话题需要借助 ROS Qt 包提供的功能。首先,我们需要在 CMakeLists.txt 文件中添加对 Qt 模块的依赖。然后,在应用程序代码中,我们需要包含 Qt 的头文件,并在主函数中初始化 ROS 节点。 接下来,我们可以使用 ROS Qt 包提供的 QROSNode 类创建一个 ROS 节点对象。通过调用节点对象的 subscribe() 函数,我们可以订阅指定的 ROS 话题,并设置回调函数来处理接收到的数据。回调函数会在有新数据发布到话题时自动被调用。 在回调函数中,我们可以根据需要处理接收到的数据,并更新 Qt 应用程序的界面或执行其他操作。例如,我们可以将接收到的数据显示在 Qt 的文本框或标签中,或者根据接收到的数据控制机器人的运动。 需要注意的是,为了在 Qt 应用程序中订阅 ROS 话题,我们需要确保 ROS 环境已经正确地设置,包括正确配置 ROS_MASTER_URI 和 ROS_IP。 总之,借助 ROS Qt 包,我们可以很方便地在 Qt 应用程序中订阅 ROS 话题,从而实现对机器人软件的控制和监测。 ### 回答2: 在ROS中,我们可以使用Qt来订阅ROS话题,以便接收和处理来自其他节点发布的消息。 首先,我们需要在Qt应用程序中包含ROS和rosbridge库,这样才能与ROS系统进行通信。接下来,我们需要创建一个ROS节点,并使用ros::init()函数来初始化ROS。然后,我们可以创建一个Qt Widget界面,用于显示接收到的消息。 接下来,我们需要定义一个ROS话题订阅者,用于接收特定话题的消息。在Qt中,我们可以使用QObject类的子类来实现订阅者。在订阅者类的构造函数中,我们可以使用ros::NodeHandle对象来订阅特定的ROS话题,并指定回调函数来处理接收到的消息。 在回调函数中,我们可以将接收到的消息转换成我们需要的数据类型,并进行处理。例如,如果我们接收到的消息是一个包含字符串数据的std_msgs::String消息,我们可以使用QString来存储和显示该字符串。 最后,在我们的Qt Widget界面中,我们可以使用Qt信号和槽机制来将接收到的消息发送到需要显示的部件。例如,我们可以将接收到的消息通过一个QLabel部件来显示在界面上。 需要注意的是,在订阅ROS话题之前,我们需要确保ROS系统已经启动,并且所需的ROS节点和话题已经被创建。 通过上述步骤,我们可以使用Qt来订阅ROS话题,并实时接收、处理和显示来自其他节点发布的消息。 ### 回答3: Qt是一个流行的跨平台应用程序开发框架,它可以用于开发各种类型的应用程序,包括机器人的控制和监控系统。ROS(Robot Operating System)是一个用于机器人软件开发的开源框架,它提供了一系列的工具、库和通信机制,可以方便地实现机器人的感知、控制和协作。 在Qt中订阅ROS话题可以通过使用ROS的Qt增加库(roscpp库)来实现。首先,需要在Qt项目中添加roscpp库的依赖关系。然后,在Qt应用程序中引用roscpp库,并使用roscpp提供的函数来订阅ROS话题。 订阅ROS话题的过程如下: 1. 创建一个Qt的类,用于处理从ROS话题接收到的数据。 2. 在该类的构造函数中,初始化ROS节点,并创建一个订阅器对象。传入订阅器的参数包括订阅的话题名称、订阅消息的类型、回调函数等。 3. 编写回调函数,用于接收到消息后的处理操作。回调函数的参数与订阅的消息类型相匹配。 4. 在订阅器对象中注册回调函数,以便在接收到新消息时调用。 5. 启动ROS节点的事件循环,以便接收消息并调用相应的回调函数。 通过这样的方式,可以在Qt应用程序中实时地订阅ROS话题,并处理接收到的数据。在接收到新消息时,回调函数会被调用,可以在其中更新界面、执行控制操作或进行其他处理。这样,Qt应用程序就与ROS框架进行了集成,可以实现更方便、灵活的机器人软件开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值