2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ROS2講座04 Qtの基本機能

Last updated at Posted at 2023-06-28

環境

この記事は以下の環境で動いています。

項目
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 

qt_sample1.png

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

qt_sample2.png

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

qt_sample3.gif

UI要素を操作することで別のUI要素のアクションが起きます。

目次ページへのリンク

ROS2講座の目次へのリンク

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?