├── .gitignore ├── CMakeLists.txt ├── README.md ├── include ├── mainwindow.h └── qml_mediator.h ├── package.xml ├── src ├── display.qrc ├── line_display.qml ├── listener.cpp ├── listener_qml.cpp ├── listener_qt.cpp ├── listener_wig.cpp ├── mainwindow.cpp ├── talker.cpp ├── talker_qml.cpp ├── talker_qt.cpp └── talker_wig.cpp ├── talker_wig.pro └── ui └── mainwindow.ui /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | bin/ 3 | lib/ 4 | msg_gen/ 5 | srv_gen/ 6 | msg/*Action.msg 7 | msg/*ActionFeedback.msg 8 | msg/*ActionGoal.msg 9 | msg/*ActionResult.msg 10 | msg/*Feedback.msg 11 | msg/*Goal.msg 12 | msg/*Result.msg 13 | msg/_*.py 14 | 15 | # Generated by dynamic reconfigure 16 | *.cfgc 17 | /cfg/cpp/ 18 | /cfg/*.py 19 | 20 | # Ignore generated docs 21 | *.dox 22 | *.wikidoc 23 | 24 | # eclipse stuff 25 | .project 26 | .cproject 27 | 28 | # qcreator stuff 29 | CMakeLists.txt.user 30 | 31 | srv/_*.py 32 | *.pcd 33 | *.pyc 34 | qtcreator-* 35 | *.user 36 | 37 | /planning/cfg 38 | /planning/docs 39 | /planning/src 40 | 41 | *~ 42 | 43 | # Emacs 44 | .#* 45 | 46 | # Catkin custom files 47 | CATKIN_IGNORE 48 | 49 | ## Core latex/pdflatex auxiliary files: 50 | *.aux 51 | *.lof 52 | *.log 53 | *.lot 54 | *.fls 55 | *.out 56 | *.toc 57 | *.fmt 58 | *.fot 59 | *.cb 60 | *.cb2 61 | 62 | ## Intermediate documents: 63 | *.dvi 64 | *.xdv 65 | *-converted-to.* 66 | # these rules might exclude image files for figures etc. 67 | # *.ps 68 | # *.eps 69 | *.pdf 70 | 71 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 72 | *.bbl 73 | *.bcf 74 | *.blg 75 | *-blx.aux 76 | *-blx.bib 77 | *.run.xml 78 | 79 | ## Build tool auxiliary files: 80 | *.fdb_latexmk 81 | *.synctex 82 | *.synctex(busy) 83 | *.synctex.gz 84 | *.synctex.gz(busy) 85 | *.pdfsync 86 | 87 | ## Auxiliary and intermediate files from other packages: 88 | # algorithms 89 | *.alg 90 | *.loa 91 | 92 | # achemso 93 | acs-*.bib 94 | 95 | # amsthm 96 | *.thm 97 | 98 | # beamer 99 | *.nav 100 | *.pre 101 | *.snm 102 | *.vrb 103 | 104 | # changes 105 | *.soc 106 | 107 | # cprotect 108 | *.cpt 109 | 110 | # elsarticle (documentclass of Elsevier journals) 111 | *.spl 112 | 113 | # endnotes 114 | *.ent 115 | 116 | # fixme 117 | *.lox 118 | 119 | # feynmf/feynmp 120 | *.mf 121 | *.mp 122 | *.t[1-9] 123 | *.t[1-9][0-9] 124 | *.tfm 125 | 126 | #(r)(e)ledmac/(r)(e)ledpar 127 | *.end 128 | *.?end 129 | *.[1-9] 130 | *.[1-9][0-9] 131 | *.[1-9][0-9][0-9] 132 | *.[1-9]R 133 | *.[1-9][0-9]R 134 | *.[1-9][0-9][0-9]R 135 | *.eledsec[1-9] 136 | *.eledsec[1-9]R 137 | *.eledsec[1-9][0-9] 138 | *.eledsec[1-9][0-9]R 139 | *.eledsec[1-9][0-9][0-9] 140 | *.eledsec[1-9][0-9][0-9]R 141 | 142 | # glossaries 143 | *.acn 144 | *.acr 145 | *.glg 146 | *.glo 147 | *.gls 148 | *.glsdefs 149 | 150 | # gnuplottex 151 | *-gnuplottex-* 152 | 153 | # gregoriotex 154 | *.gaux 155 | *.gtex 156 | 157 | # hyperref 158 | *.brf 159 | 160 | # knitr 161 | *-concordance.tex 162 | # TODO Comment the next line if you want to keep your tikz graphics files 163 | *.tikz 164 | *-tikzDictionary 165 | 166 | # listings 167 | *.lol 168 | 169 | # makeidx 170 | *.idx 171 | *.ilg 172 | *.ind 173 | *.ist 174 | 175 | # minitoc 176 | *.maf 177 | *.mlf 178 | *.mlt 179 | *.mtc[0-9]* 180 | *.slf[0-9]* 181 | *.slt[0-9]* 182 | *.stc[0-9]* 183 | 184 | # minted 185 | _minted* 186 | *.pyg 187 | 188 | # morewrites 189 | *.mw 190 | 191 | # nomencl 192 | *.nlo 193 | 194 | # pax 195 | *.pax 196 | 197 | # pdfpcnotes 198 | *.pdfpc 199 | 200 | # sagetex 201 | *.sagetex.sage 202 | *.sagetex.py 203 | *.sagetex.scmd 204 | 205 | # scrwfile 206 | *.wrt 207 | 208 | # sympy 209 | *.sout 210 | *.sympy 211 | sympy-plots-for-*.tex/ 212 | 213 | # pdfcomment 214 | *.upa 215 | *.upb 216 | 217 | # pythontex 218 | *.pytxcode 219 | pythontex-files-*/ 220 | 221 | # thmtools 222 | *.loe 223 | 224 | # TikZ & PGF 225 | *.dpth 226 | *.md5 227 | *.auxlock 228 | 229 | # todonotes 230 | *.tdo 231 | 232 | # easy-todo 233 | *.lod 234 | 235 | # xindy 236 | *.xdy 237 | 238 | # xypic precompiled matrices 239 | *.xyc 240 | 241 | # endfloat 242 | *.ttt 243 | *.fff 244 | 245 | # Latexian 246 | TSWLatexianTemp* 247 | 248 | ## Editors: 249 | # WinEdt 250 | *.bak 251 | *.sav 252 | 253 | # Texpad 254 | .texpadtmp 255 | 256 | # Kile 257 | *.backup 258 | 259 | # KBibTeX 260 | *~[0-9]* 261 | 262 | # auto folder when using emacs and auctex 263 | /auto/* 264 | 265 | # expex forward references with \gathertags 266 | *-tags.tex -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(pubsub) 3 | 4 | ## Compile as C++11, supported in ROS Kinetic and newer 5 | add_compile_options(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | find_package(catkin REQUIRED COMPONENTS 9 | roscpp 10 | std_msgs 11 | ) 12 | 13 | # Find Qt5 libraries 14 | find_package(Qt5 REQUIRED COMPONENTS 15 | Core 16 | Qml 17 | Quick 18 | Widgets 19 | ) 20 | 21 | # Configuration to make Qt compiles go smoother 22 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 23 | set(CMAKE_AUTOMOC ON) 24 | include_directories( ${CMAKE_BINARY_DIR} ) 25 | 26 | # Configure Catkin dependencies 27 | catkin_package( 28 | CATKIN_DEPENDS 29 | roscpp 30 | std_msgs 31 | ) 32 | 33 | include_directories( 34 | include 35 | ${catkin_INCLUDE_DIRS} 36 | ) 37 | 38 | ############################### 39 | # Basic, non-qt talker/listener 40 | add_executable(listener src/listener.cpp) 41 | add_executable(talker src/talker.cpp) 42 | 43 | 44 | target_link_libraries(listener 45 | ${catkin_LIBRARIES} 46 | ) 47 | 48 | target_link_libraries(talker 49 | ${catkin_LIBRARIES} 50 | ) 51 | 52 | ################################################ 53 | # Cmd line talker/listener running qt event loop 54 | add_executable(listener_qt src/listener_qt.cpp) 55 | add_executable(talker_qt src/talker_qt.cpp) 56 | 57 | # Configure Qt5 Modules 58 | # Equivalent to doing 59 | # Qt += Core 60 | # In Qt .pro file 61 | qt5_use_modules(listener_qt Core) 62 | qt5_use_modules(talker_qt Core) 63 | 64 | target_link_libraries(listener_qt 65 | ${catkin_LIBRARIES} 66 | ) 67 | 68 | target_link_libraries(talker_qt 69 | ${catkin_LIBRARIES} 70 | ) 71 | 72 | ###################################### 73 | # Talker and Listener using QML gui 74 | 75 | # Run MOC on headers of Q_OBJECT classes 76 | set(MOC_HDRS include/qml_mediator.h) 77 | qt5_wrap_cpp(MOC_SRCS ${MOC_HDRS}) 78 | 79 | # Run RCC on QRC file 80 | set(RCC_FILES src/display.qrc) 81 | qt5_add_resources(RCC_SOURCES ${RCC_FILES}) 82 | 83 | # Build executables with source, MOC result files, RCC result files 84 | add_executable(listener_qml src/listener_qml.cpp ${MOC_SRCS} ${RCC_SOURCES}) 85 | add_executable(talker_qml src/talker_qml.cpp ${MOC_SRCS} ${RCC_SOURCES}) 86 | 87 | # Configure Qt5 Modules 88 | # Equivalent to doing 89 | # Qt += Core Qml Quick 90 | # In Qt .pro file 91 | qt5_use_modules(listener_qml Core Qml Quick) 92 | qt5_use_modules(talker_qml Core Qml Quick) 93 | 94 | target_link_libraries(listener_qml 95 | ${catkin_LIBRARIES} 96 | ) 97 | 98 | target_link_libraries(talker_qml 99 | ${catkin_LIBRARIES} 100 | ) 101 | 102 | ######################################## 103 | # Talker and Listener using QWidgets gui 104 | 105 | # Run MOC on headers of Q_OBJECT classes 106 | set(MOC_HDRS include/mainwindow.h) 107 | qt5_wrap_cpp(MOC_SRCS ${MOC_HDRS}) 108 | 109 | # Run UIC on ui definitions 110 | set(UI_FILES ui/mainwindow.ui) 111 | qt5_wrap_ui(UI_SRCS ${UI_FILES}) 112 | 113 | # Build executables with source, MOC result files, UIC result files 114 | add_executable(talker_wig src/talker_wig.cpp src/mainwindow.cpp ${MOC_SRCS} ${UI_SRCS}) 115 | add_executable(listener_wig src/listener_wig.cpp src/mainwindow.cpp ${MOC_SRCS} ${UI_SRCS}) 116 | 117 | # Configure Qt5 Modules 118 | # Equivalent to doing 119 | # Qt += Core Widgets 120 | # In Qt .pro file 121 | qt5_use_modules(talker_wig Core Widgets) 122 | qt5_use_modules(listener_wig Core Widgets) 123 | 124 | target_link_libraries(talker_wig 125 | ${catkin_LIBRARIES} 126 | ) 127 | 128 | target_link_libraries(listener_wig 129 | ${catkin_LIBRARIES} 130 | ) 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ROS_QML_Example 2 | A test project to show how to use QT5 QML and Widgets in a ROS node 3 | 4 | This project was created so that I could work out some workflow kinks when using ROS and QT5 together to create a QML or QtWidgets gui node. 5 | The repo should be pulled into the /src directory of a catkin workspace and built with catkin_make. 6 | All the examples are in the ros package 'pubsub'. 7 | 8 | There are four examples in the repo, each consisting of a 'talker' and 'listener' program: 9 | * listener/talker 10 | * listener_qt/talker_qt 11 | * listener_qml/talker_qml 12 | * listener_wig/talker_wig 13 | 14 | The 'talker' program publishes a message every 5 seconds and the 'listener' program listens to them. 15 | All the talkers should be compatible with all the listeners 16 | 17 | Example run 18 | 19 | In terminal 1 20 | ``` 21 | roscore 22 | ``` 23 | 24 | In terminal 2 25 | ``` 26 | rosrun pubsub talker_qml 27 | ``` 28 | 29 | In terminal 3 30 | ``` 31 | rosrun pubsub listener_qml 32 | ``` 33 | 34 | Note: QML modules are not usually installed by default on Ubuntu 16.04; users will have to install them before the node will run. For example, to run the qml examples in this package, you will need to either install Qt or run the following command to install the QtQuick.Controls module: 35 | ``` 36 | sudo apt -y install qml-module-qtquick-controls 37 | ``` 38 | 39 | Note 2: The .pro file is there so that one can use QtCreator for modifying the code. It is possible to source qt and have it run catkin make when you build; but it can lead to some strange build errors that don't actually matter, so I don't recommend this unless you know what you're doing 40 | -------------------------------------------------------------------------------- /include/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include "ros/ros.h" 5 | #include "std_msgs/String.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace Ui { 11 | class MainWindow; 12 | } 13 | 14 | class MainWindow : public QMainWindow 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit MainWindow(QWidget *parent = 0); 20 | ~MainWindow(); 21 | 22 | void addString(const QString& s) 23 | { 24 | newString(s); 25 | } 26 | 27 | //Emit this as a signal to be caught locally in order to prevent race conditions 28 | void addString(const std_msgs::String::ConstPtr& msg) 29 | { 30 | newString("I heard: [" + QString(msg->data.c_str()) + "]"); 31 | } 32 | 33 | private: 34 | Ui::MainWindow *ui; 35 | 36 | 37 | signals: 38 | void stringsChanged(); 39 | void newString(QString s); 40 | 41 | private slots: 42 | void newStringSlot(QString txt); 43 | }; 44 | 45 | #endif // MAINWINDOW_H 46 | -------------------------------------------------------------------------------- /include/qml_mediator.h: -------------------------------------------------------------------------------- 1 | #ifndef QML_MEDIATOR_H 2 | #define QML_MEDIATOR_H 3 | 4 | #include "ros/ros.h" 5 | #include "std_msgs/String.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class QMLMediator : public QObject 12 | { 13 | Q_OBJECT 14 | 15 | Q_PROPERTY(QVariantList strings READ getStrings NOTIFY stringsChanged); 16 | QVariantList m_strings; 17 | 18 | public: 19 | QMLMediator(QObject* parent = nullptr) 20 | { 21 | connect(this, &QMLMediator::newString, this, &QMLMediator::newStringSlot); 22 | } 23 | 24 | QVariantList getStrings() 25 | { 26 | return m_strings; 27 | } 28 | 29 | void addString(const QString& s) 30 | { 31 | newString(s); 32 | } 33 | 34 | //Emit this as a signal to be caught locally in order to prevent race conditions 35 | void addString(const std_msgs::String::ConstPtr& msg) 36 | { 37 | newString("I heard: [" + QString(msg->data.c_str()) + "]"); 38 | } 39 | 40 | signals: 41 | void stringsChanged(); 42 | void newString(QString s); 43 | 44 | private slots: 45 | void newStringSlot(QString s) 46 | { 47 | m_strings.append(s); 48 | stringsChanged(); 49 | } 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | pubsub 4 | 0.0.1 5 | Example package using QT5 QML in a ROS node 6 | 7 | ipiano 8 | 9 | TODO 10 | 11 | catkin 12 | 13 | roscpp 14 | std_msgs 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/display.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | line_display.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/line_display.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Window 2.2 3 | import QtQuick.Controls 1.2 4 | 5 | Window { 6 | ScrollView { 7 | anchors.fill: parent 8 | anchors.leftMargin: 10 9 | anchors.rightMargin: 10 10 | anchors.topMargin: 10 11 | anchors.bottomMargin: 10 12 | 13 | ListView { 14 | anchors.fill: parent 15 | 16 | model: mediator.strings 17 | delegate: Text { 18 | anchors.left: parent.left 19 | anchors.right: parent.right 20 | height: 25 21 | 22 | text: modelData 23 | } 24 | } 25 | } 26 | 27 | visible: true 28 | width: 360 29 | height: 360 30 | } -------------------------------------------------------------------------------- /src/listener.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | using namespace std; 5 | 6 | void dataCallback(const std_msgs::String::ConstPtr& msg) 7 | { 8 | ROS_INFO("I heard: [%s]", msg->data.c_str()); 9 | } 10 | 11 | int main(int argc, char** argv) 12 | { 13 | ros::init(argc, argv, "listener"); 14 | 15 | ros::NodeHandle node; 16 | 17 | ros::Subscriber sub = node.subscribe("chatter", 1000, dataCallback); 18 | 19 | ros::spin(); 20 | 21 | return 0; 22 | } -------------------------------------------------------------------------------- /src/listener_qml.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "qml_mediator.h" 21 | 22 | using namespace std; 23 | 24 | int main(int argc, char** argv) 25 | { 26 | //Init ros stuff 27 | ros::init(argc, argv, "listener"); 28 | ros::NodeHandle node; 29 | 30 | //Init Qt 31 | QGuiApplication app(argc, argv); 32 | QMLMediator mediate(&app); 33 | ros::Subscriber sub = node.subscribe("chatter", 1000, &QMLMediator::addString, &mediate); 34 | 35 | //Start ros in separate thread, and trigger Qt shutdown when it exits 36 | //If Qt exits before ros, be sure to shutdown ros 37 | QFutureWatcher rosThread; 38 | rosThread.setFuture(QtConcurrent::run(&ros::spin)); 39 | QObject::connect(&rosThread, &QFutureWatcher::finished, &app, &QCoreApplication::quit); 40 | QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ros::shutdown();}); 41 | 42 | QQmlApplicationEngine engine(&app); 43 | engine.rootContext()->setContextProperty("mediator", &mediate); 44 | engine.load(QUrl("qrc:///qml/line_display.qml")); 45 | 46 | //Start qt app 47 | return app.exec(); 48 | } 49 | -------------------------------------------------------------------------------- /src/listener_qt.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | void dataCallback(const std_msgs::String::ConstPtr& msg) 13 | { 14 | ROS_INFO("I heard: [%s]", msg->data.c_str()); 15 | } 16 | 17 | int main(int argc, char** argv) 18 | { 19 | //Init ros stuff 20 | ros::init(argc, argv, "listener"); 21 | ros::NodeHandle node; 22 | ros::Subscriber sub = node.subscribe("chatter", 1000, dataCallback); 23 | 24 | //Init Qt 25 | QCoreApplication app(argc, argv); 26 | 27 | //Start ros in separate thread, and trigger Qt shutdown when it exits 28 | //If Qt exits before ros, be sure to shutdown ros 29 | QFutureWatcher rosThread; 30 | rosThread.setFuture(QtConcurrent::run(&ros::spin)); 31 | QObject::connect(&rosThread, &QFutureWatcher::finished, &app, &QCoreApplication::quit); 32 | QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ros::shutdown();}); 33 | 34 | //Start qt app 35 | return app.exec(); 36 | } 37 | -------------------------------------------------------------------------------- /src/listener_wig.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "mainwindow.h" 19 | 20 | using namespace std; 21 | 22 | int main(int argc, char** argv) 23 | { 24 | //Init ros stuff 25 | ros::init(argc, argv, "listener"); 26 | ros::NodeHandle node; 27 | 28 | //Init Qt 29 | QApplication app(argc, argv); 30 | MainWindow w; 31 | ros::Subscriber sub = node.subscribe("chatter", 1000, &MainWindow::addString, &w); 32 | 33 | //Start ros in separate thread, and trigger Qt shutdown when it exits 34 | //If Qt exits before ros, be sure to shutdown ros 35 | QFutureWatcher rosThread; 36 | rosThread.setFuture(QtConcurrent::run(&ros::spin)); 37 | QObject::connect(&rosThread, &QFutureWatcher::finished, &app, &QCoreApplication::quit); 38 | QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ros::shutdown();}); 39 | 40 | //Show the window 41 | w.show(); 42 | 43 | //Start qt app 44 | return app.exec(); 45 | } 46 | -------------------------------------------------------------------------------- /src/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | connect(this, &MainWindow::newString, this, &MainWindow::newStringSlot); 10 | } 11 | 12 | MainWindow::~MainWindow() 13 | { 14 | delete ui; 15 | } 16 | 17 | void MainWindow::newStringSlot(QString txt) 18 | { 19 | ui->list_lines->addItem(txt); 20 | } 21 | -------------------------------------------------------------------------------- /src/talker.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main(int argc, char** argv) 11 | { 12 | ros::init(argc, argv, "talker"); 13 | 14 | ros::NodeHandle node; 15 | 16 | ros::Publisher pub = node.advertise("chatter", 1000); 17 | 18 | int i=0; 19 | while(ros::ok()) 20 | { 21 | std_msgs::String msg; 22 | 23 | msg.data = string("Message #" + to_string(i++)).c_str(); 24 | ROS_INFO("Sending [%s]", msg.data.c_str()); 25 | 26 | pub.publish(msg); 27 | 28 | ros::spinOnce(); 29 | 30 | this_thread::sleep_for(chrono::seconds(5)); 31 | } 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /src/talker_qml.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "qml_mediator.h" 23 | 24 | using namespace std; 25 | 26 | int main(int argc, char** argv) 27 | { 28 | //Init ros stuff 29 | ros::init(argc, argv, "talker"); 30 | ros::NodeHandle node; 31 | ros::Publisher pub = node.advertise("chatter", 1000); 32 | 33 | //Init Qt 34 | QGuiApplication app(argc, argv); 35 | QMLMediator mediate(&app); 36 | 37 | //Start ros in separate thread, and trigger Qt shutdown when it exits 38 | //If Qt exits before ros, be sure to shutdown ros 39 | QFutureWatcher rosThread; 40 | rosThread.setFuture(QtConcurrent::run(&ros::spin)); 41 | QObject::connect(&rosThread, &QFutureWatcher::finished, &app, &QCoreApplication::quit); 42 | QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ros::shutdown();}); 43 | 44 | //5 second timer to publish 45 | QTimer sec5; 46 | sec5.setInterval(5000); 47 | 48 | //Set up slot for 5 second timer 49 | int i=0; 50 | QObject::connect(&sec5, &QTimer::timeout, [&]() 51 | { 52 | std_msgs::String msg; 53 | 54 | msg.data = string("Message #" + to_string(i++)).c_str(); 55 | mediate.addString("Sending [" + QString(msg.data.c_str()) + "]"); 56 | 57 | pub.publish(msg); 58 | }); 59 | 60 | QQmlApplicationEngine engine(&app); 61 | engine.rootContext()->setContextProperty("mediator", &mediate); 62 | engine.load(QUrl("qrc:///qml/line_display.qml")); 63 | 64 | //Start timer 65 | sec5.start(); 66 | 67 | //Start main app 68 | return app.exec(); 69 | } 70 | -------------------------------------------------------------------------------- /src/talker_qt.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | int main(int argc, char** argv) 18 | { 19 | //Init ros stuff 20 | ros::init(argc, argv, "talker"); 21 | ros::NodeHandle node; 22 | ros::Publisher pub = node.advertise("chatter", 1000); 23 | 24 | //Init Qt 25 | QCoreApplication app(argc, argv); 26 | 27 | //Start ros in separate thread, and trigger Qt shutdown when it exits 28 | //If Qt exits before ros, be sure to shutdown ros 29 | QFutureWatcher rosThread; 30 | rosThread.setFuture(QtConcurrent::run(&ros::spin)); 31 | QObject::connect(&rosThread, &QFutureWatcher::finished, &app, &QCoreApplication::quit); 32 | QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ros::shutdown();}); 33 | 34 | //5 second timer to publish 35 | QTimer sec5; 36 | sec5.setInterval(5000); 37 | 38 | //Set up slot for 5 second timer 39 | int i=0; 40 | QObject::connect(&sec5, &QTimer::timeout, [&]() 41 | { 42 | std_msgs::String msg; 43 | 44 | msg.data = string("Message #" + to_string(i++)).c_str(); 45 | ROS_INFO("Sending [%s]", msg.data.c_str()); 46 | 47 | pub.publish(msg); 48 | }); 49 | 50 | //Start timer 51 | sec5.start(); 52 | 53 | //Start main app 54 | return app.exec(); 55 | } 56 | -------------------------------------------------------------------------------- /src/talker_wig.cpp: -------------------------------------------------------------------------------- 1 | #include "ros/ros.h" 2 | #include "std_msgs/String.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "mainwindow.h" 20 | 21 | using namespace std; 22 | 23 | int main(int argc, char** argv) 24 | { 25 | //Init ros stuff 26 | ros::init(argc, argv, "talker"); 27 | ros::NodeHandle node; 28 | ros::Publisher pub = node.advertise("chatter", 1000); 29 | 30 | //Init Qt 31 | QApplication app(argc, argv); 32 | MainWindow w; 33 | 34 | //Start ros in separate thread, and trigger Qt shutdown when it exits 35 | //If Qt exits before ros, be sure to shutdown ros 36 | QFutureWatcher rosThread; 37 | rosThread.setFuture(QtConcurrent::run(&ros::spin)); 38 | QObject::connect(&rosThread, &QFutureWatcher::finished, &app, &QCoreApplication::quit); 39 | QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ros::shutdown();}); 40 | 41 | //5 second timer to publish 42 | QTimer sec5; 43 | sec5.setInterval(5000); 44 | 45 | //Set up slot for 5 second timer 46 | int i=0; 47 | QObject::connect(&sec5, &QTimer::timeout, [&]() 48 | { 49 | std_msgs::String msg; 50 | 51 | msg.data = string("Message #" + to_string(i++)).c_str(); 52 | w.addString("Sending [" + QString(msg.data.c_str()) + "]"); 53 | 54 | pub.publish(msg); 55 | }); 56 | 57 | //Start timer 58 | sec5.start(); 59 | 60 | //Show main window 61 | w.show(); 62 | 63 | //Start main app 64 | return app.exec(); 65 | } 66 | -------------------------------------------------------------------------------- /talker_wig.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-09-21T12:16:14 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = talker_wig 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | INCLUDEPATH += include 26 | 27 | SOURCES += \ 28 | src/talker_wig.cpp \ 29 | src/mainwindow.cpp \ 30 | src/listener_wig.cpp \ 31 | src/listener_qml.cpp \ 32 | src/listener_qt.cpp \ 33 | src/talker_qml.cpp \ 34 | src/talker_qt.cpp 35 | 36 | HEADERS += \ 37 | include/mainwindow.h \ 38 | include/qml_mediator.h 39 | 40 | FORMS += \ 41 | ui/mainwindow.ui 42 | 43 | DISTFILES += CMakeLists.txt 44 | -------------------------------------------------------------------------------- /ui/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------