環境
この記事は以下の環境で動いています。
項目 | 値 |
---|---|
CPU | Core i5-8250U |
Ubuntu | 22.04 |
ROS2 | Humble |
Qt | 5.15.3 |
概要
ROS2ではGUIライブライrであるQtをよく使用します。Rvizのパネル表示やRqtでも使われています。
ここでは基本的なQtのプログラムを解説します。
基本のウィンドウの表示
C++コード
qt_lecture/src/qt_sample1/main.cpp
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QLabel* label = new QLabel("######## basic1 ########");
label->show();
return app.exec();
}
-
QApplication app(argc, argv);
はQtのプログラムで最初に必要な記述です。 -
QLabel
はWidgetの一種です。WidgetはUI要素に対応するクラスでQLabel
はテキスト表示を行います。- クラスのインスタンスを生成した後から文字を設定することもできますが、今回のようにコンストラクターでも文字を設定できます。
-
QLabel
のメソッド等詳細は公式サイトが詳しいです。 -
show()
メソッドを呼ぶことでGUIに表示します。 -
app.exec()
を呼ぶことでGUIが開始します。
cmake
qt_lecture/CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(qt_lecture)
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rviz_common REQUIRED)
add_executable(qt_sample1
src/qt_sample1/main.cpp)
ament_target_dependencies(qt_sample1
"rviz_common"
)
install(
TARGETS qt_sample1
DESTINATION lib/${PROJECT_NAME}
)
ament_package()
- Qtのcmakeは直に書くといろいろ面倒なのでROS2のマクロを使います。
- rviz_commonへの依存を記述すれば、Qtへの依存が入ります。
ビルド&実行
ビルド
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build
実行
ros2 run qt_lecture qt_sample1
GUIが表示されます。
レイアウト
ここまでの方法では1つのWidgetしか表示できません。Layoutを使うことで複数のWidgetを表示することが出来ます。
c++
qt_lecture/src/qt_sample2/main.cpp
#include <QApplication>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QPushButton>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget* window1 = new QWidget;
QPushButton* button1A = new QPushButton("Button 1A");
QPushButton* button1B = new QPushButton("Button 1B");
QPushButton* button1C = new QPushButton("Button 1C");
QHBoxLayout* layout1 = new QHBoxLayout;
layout1->addWidget(button1A);
layout1->addWidget(button1B);
layout1->addWidget(button1C);
window1->setLayout(layout1);
window1->show();
QWidget* window2 = new QWidget;
QPushButton* button2A = new QPushButton("Button 2A");
QPushButton* button2B = new QPushButton("Button 2B");
QPushButton* button2C = new QPushButton("Button 2C");
QVBoxLayout* layout2 = new QVBoxLayout;
layout2->addWidget(button2A);
layout2->addWidget(button2B);
layout2->addWidget(button2C);
window2->setLayout(layout2);
window2->show();
QWidget* window3 = new QWidget;
QPushButton* button3A = new QPushButton("Button 3A");
QPushButton* button3B = new QPushButton("Button 3B");
QPushButton* button3C = new QPushButton("Button 3C");
QGridLayout* layout3 = new QGridLayout;
layout3->addWidget(button3A,0,0);
layout3->addWidget(button3B,0,1);
layout3->addWidget(button3C,1,0,1,2);
window3->setLayout(layout3);
window3->show();
return app.exec();
}
- ここでは3種類のLayoutを使います。
-
QHBoxLayout
は横一列に並べます。addWidget()
で最初に追加した要素が左に来ます。 -
QVBoxLayout
は縦一列に並べます。addWidget()
で最初に追加した要素が上に来ます。 -
QGridLayout
はグリッド上に並べます。addWidget()
でマス目中の位置とサイズを指定します。
-
-
QPushButton
は押しボタンに対応するWidgetです。
ビルド&実行
ビルド
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build
実行
ros2 run qt_lecture qt_sample2
3つのウィンドウが表示されます。
Signal-Slotの接続
ここまでではGUI要素が表示をしているだけです。GUI同士が連携するためにはSignalとSlotという機構を使います。
ROSでのpub-subのようなもので2つのwidget間をつなぐ仕組みで、特定のイベントが起きるとあるWidgetのSignalが発生します。そうすると紐づけられた別のWidgetのSlotを実行することが出来ます。
SignalとSlotはconnect
関数で紐づけることが出来ます。
qt_lecture/src/qt_sample3/main.cpp
#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget* window = new QWidget;
QVBoxLayout* layout = new QVBoxLayout;
QPushButton* button = new QPushButton("Quit");
QLineEdit* edit = new QLineEdit("");
QLabel* label = new QLabel("");
layout->addWidget(button);
layout->addWidget(edit);
layout->addWidget(label);
window->setLayout(layout);
QObject::connect(button, &QPushButton::clicked, &app, &QApplication::quit);
QObject::connect(edit, &QLineEdit::textChanged, label, &QLabel::setText);
window->show();
return app.exec();
}
- 今回は3つの押しボタン(
QPushButton
)、文字入力(QLineEdit
)、文字表示(QLabel
)の3つのWidgetが登場します。 - 押しボタンが押されたときに、ウィンドウが終了するように
connect
で設定します。- 押しボタンが押されたときに
QPushButton::clicked
のsignalが発生します。 -
QApplication::quit
のslotによって、windowを終了します。
- 押しボタンが押されたときに
- 文字入力した内容が、文字表示に反映されます。
- 文字入力の内容が変更されたときに
QLineEdit::textChanged
のsignalが発生します。 -
QLabel::setText
のslotによって、文字表示の内容を設定します。
- 文字入力の内容が変更されたときに
ビルド&実行
ビルド
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build
実行
ros2 run qt_lecture qt_sample3
UI要素を操作することで別のUI要素のアクションが起きます。