環境
この記事は以下の環境で動いています。
項目 | 値 |
---|---|
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
- ボタンを押すと文字入力の内容がラベルにコピーします。
- またボタンを押すとボタンの文字が一瞬「Done」になり、しばらく後「Set」に戻ります。