1
1

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講座05 Qtをクラスで使う

Last updated at Posted at 2023-06-29

環境

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

項目
CPU Core i5-8250U
Ubuntu 22.04
ROS2 Humble
Qt 5.15.3

概要

QtでGUI要素のシグナルでごくじ処理をするためにはClassの記述が必要です。
Qtのクラスの記述にはMOCや独自マクロの記述が必要です。

ソースコード

C++コード

qt_lecture/src/qt_sample4/main_dialog.hpp
#include <QDialog>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QTimer>

class MainDialog : public QDialog
{
  Q_OBJECT
public:
  MainDialog(QWidget *parent);

public Q_SLOTS:
  void setLabelText();
  void clearButtonText();

Q_SIGNALS:
  void modifyText(QString);

private:
  QLabel *label_;
  QLineEdit *lineEdit_;
  QPushButton *setButton_;
  QTimer *timer_;
};
  • GUIを記述するclassのheaderです。
  • QDialogはGUIの画面を表すクラスです。これを継承して独自処理を追加します。
  • Qtのクラスでは独自のマクロの記述が必要です。
    • Q_OBJECTはQtのマクロでQtのクラスの記述の最初に書きます。
    • Q_SLOTSはslot関数の定義の前に記述するマクロです。
    • Q_SIGNALSはsignalの前に記述するマクロです(こちらはアクセス指定子は必要ないです)。
qt_lecture/src/qt_sample4/main_dialog.cpp
#include <QDialog>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QVBoxLayout>

#include "main_dialog.hpp"

MainDialog::MainDialog(QWidget *parent) : QDialog(parent)
{
  label_ = new QLabel(tr("empty"));
  setButton_ = new QPushButton(tr("Set"));
  lineEdit_ = new QLineEdit;
  timer_ = new QTimer;

  connect(setButton_, &QPushButton::clicked, this, &MainDialog::setLabelText);
  connect(timer_, &QTimer::timeout, this, &MainDialog::clearButtonText);
  connect(this, &MainDialog::modifyText, label_, &QLabel::setText);

  QVBoxLayout *layout = new QVBoxLayout;
  layout->addWidget(label_);
  layout->addWidget(lineEdit_);
  layout->addWidget(setButton_);
  setLayout(layout);
}

void MainDialog::setLabelText()
{
  QString text = lineEdit_->text();
  setButton_->setText("Done");
  timer_->start(500);
  Q_EMIT modifyText(text);
}

void MainDialog::clearButtonText()
{
  setButton_->setText("Set");
}
  • コンストラクタでGUIの設定をしています。
  • slot関数としてsetLabelText()を設定します。この中でイベント発生時に実行したい処理を書きます。
    • connect関数での設定により、押しボタンを押したときにイベントが起きます。
  • signal関数としてmodifyText()を設定しています。Q_EMIT modifyText(text);と記述することでsignalを発生できます。
    • connect関数での設定により、このsignalが発生したときにラベルの文字が変更になります。
  • QTimerによって指定の時間後にイベントを発生する(signalを発生する)ことが出来ます。
    • timer_->start(500);で500ms後にtimeout()のシグナルが発生します。
  • ビルド時にQt特有の処理としてMeta-Object Compiler(MOC)があります。これによってヘッダーはコンパイル前にマクロ処理が行われます。まれにincludeするファイルでトラブルが起きることがあります。その時はinclude#ifndef Q_MOC_RUN~#endifで囲んでください。
qt_lecture/src/qt_sample4/main.cpp
#include <QApplication>
#include "main_dialog.hpp"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  QWidget *window = new QWidget;
  MainDialog *dialog = new MainDialog(window);
  dialog->show();
  return app.exec();
}

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)

set(CMAKE_AUTOMOC ON)

add_executable(qt_sample4
  src/qt_sample4/main.cpp
  src/qt_sample4/main_dialog.cpp
)
ament_target_dependencies(qt_sample4
  "rviz_common"
)
install(
  TARGETS qt_sample4
  DESTINATION lib/${PROJECT_NAME}
)

ament_package()
  • Qtのcmakeは直に書くといろいろ面倒なのでROS2のマクロを使います。
  • rviz_commonへの依存を記述すれば、Qtへの依存が入ります。
  • Qtのマクロを実行するためにはset(CMAKE_AUTOMOC ON)の記述が必要です。

ビルド&実行

ビルド
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build
実行
ros2 run qt_lecture qt_sample4

qt_sample4.gif

  • ボタンを押すと文字入力の内容がラベルにコピーします。
  • またボタンを押すとボタンの文字が一瞬「Done」になり、しばらく後「Set」に戻ります。

目次ページへのリンク

ROS2講座の目次へのリンク

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?