Qt/C++ による GUI ソフトウェア作成の練習 4:イベントの取得
Qt では,イベントは抽象 QEvent クラスから派生したオブジェクトです.
イベントが発生すると,適切な QEvent 派生クラスのインスタンスが作成され,その event() 関数を呼び出すことで,イベントを配信します.
ほとんどのイベント・タイプには特別なクラスがあります.QResizeEvent,QPaintEvent,QMouseEvent,QKeyEvent,QCloseEvent が代表例です.
QMouseEvent は,マウスボタンの押下,ダブルクリック,移動,その他の関連操作により発生するイベントです.
ウィジェット内でマウスボタンが押されると,ウィジェットは自動的にマウスを捕捉し,マウスボタンが離されるまでマウスイベントを受け取り続けます.
このページでは,Qt3DExtras::Qt3DWindow を継承したクラスを定義し,そのクラスで QWidget のイベントハンドラをいくつかオーバーライドしてみます.
Before : 3:レイアウト Next : 5:Qt3D による描画インフォメーション
ドキュメント
このページは,C++ クラスリファレンスの QWidget を参考にして作成しました.
マウスイベントについては,QMouseEvent Class に解説があります.
イベント全般については,Qt Core の The Event System に解説があります.
インストールした Debian パッケージ
パッケージ名(バージョン) | 注 |
g++(12.2.0) | GNU C++ コンパイラ |
make (4.3) | コンパイルを制御するユーティリティ |
qt6-base-dev(6.4.2) | Qt6 アプリケーションのビルドに使用されるヘッダ開発ファイル |
qt6-3d-dev(6.4.2) | Qt3D ライブラリを使用した Qt6 アプリケーションのビルドに使用されるヘッダ開発ファイル |
QWidget のイベントハンドラ
QWidget のページを見ると,protected メンバ関数の多くがイベントハンドラとなっています.番号を振ってみたら 26 個ありました.
これらのイベントハンドラは protected メンバなので,派生クラスでオーバーライドできます.
- virtual void actionEvent(QActionEvent *event)
- virtual void changeEvent(QEvent *event)
- virtual void closeEvent(QCloseEvent *event)
- virtual void contextMenuEvent(QContextMenuEvent *event)
- virtual void dragEnterEvent(QDragEnterEvent *event)
- virtual void dragLeaveEvent(QDragLeaveEvent *event)
- virtual void dragMoveEvent(QDragMoveEvent *event)
- virtual void dropEvent(QDropEvent *event)
- virtual void enterEvent(QEnterEvent *event)
- virtual void focusInEvent(QFocusEvent *event)
- virtual void focusOutEvent(QFocusEvent *event)
- virtual void hideEvent(QHideEvent *event)
- virtual void inputMethodEvent(QInputMethodEvent *event)
- virtual void keyPressEvent(QKeyEvent *event)
- virtual void keyReleaseEvent(QKeyEvent *event)
- virtual void leaveEvent(QEvent *event)
- virtual void mouseDoubleClickEvent(QMouseEvent *event)
- virtual void mouseMoveEvent(QMouseEvent *event)
- virtual void mousePressEvent(QMouseEvent *event)
- virtual void mouseReleaseEvent(QMouseEvent *event)
- virtual void moveEvent(QMoveEvent *event)
- virtual void paintEvent(QPaintEvent *event)
- virtual void resizeEvent(QResizeEvent *event)
- virtual void showEvent(QShowEvent *event)
- virtual void tabletEvent(QTabletEvent *event)
- virtual void wheelEvent(QWheelEvent *event)
イベントの取得と出力
レイアウトで作成したコードを変更して雛形としました.
d3_window.h と d3_window.cc は新規作成です.
レイアウトのコードを流用したコードでは,このページで追加した箇所を赤色で示しています.
ソースファイル
d3_window.h
Qt3DExtras::Qt3DWindow を継承したクラスを新規作成します.
このクラスで,基底クラスの QWidget で宣言されている仮想関数をオーバーライドするのが目的です.
#ifndef ___D3_WINDOW
#define ___D3_WINDOW
#include <Qt3DCore>
#include <Qt3DExtras>
#include <Qt3DRender>
class D3_Window : public Qt3DExtras::Qt3DWindow {
protected:
void actionEvent(QActionEvent *event);
void changeEvent(QEvent *event);
void closeEvent(QCloseEvent *event);
void contextMenuEvent(QContextMenuEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
void enterEvent(QEnterEvent *event);
void focusInEvent(QFocusEvent *event);
void focusOutEvent(QFocusEvent *event);
void hideEvent(QHideEvent *event);
void inputMethodEvent(QInputMethodEvent *event);
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void leaveEvent(QEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void moveEvent(QMoveEvent *event);
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
void showEvent(QShowEvent *event);
void tabletEvent(QTabletEvent *event);
void wheelEvent(QWheelEvent *event);
};
#endif
d3_window.cc
新規作成です.
引数のイベントを利用していない関数があるので,コンパイル時にその旨の警告が出ます.
イベントが発生すると,イベントハンドラが呼び出され,その名前が出力されます(どうやって発生させるのか知らないイベントもありますが).
マウスボタンを押した際のイベントハンドラ mousePressEvent には,ボタンに割り当てられた番号とウィンドウ上の位置を出力するコードを記述しました.
また,show_event では,基底クラス Qt3DExtras::Qt3DWindow の show_event() を呼び出しています.
そうしないと,ウィンドウの下(デスクトップとか他のウィンドウとか)が描画されてしまうからです.
#include "d3_window.h"
#include <iostream>
void D3_Window::actionEvent(QActionEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::changeEvent(QEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::closeEvent(QCloseEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::contextMenuEvent(QContextMenuEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::dragEnterEvent(QDragEnterEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::dragLeaveEvent(QDragLeaveEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::dragMoveEvent(QDragMoveEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::dropEvent(QDropEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::enterEvent(QEnterEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::focusInEvent(QFocusEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::focusOutEvent(QFocusEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::hideEvent(QHideEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::inputMethodEvent(QInputMethodEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::keyPressEvent(QKeyEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::keyReleaseEvent(QKeyEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::leaveEvent(QEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::mouseDoubleClickEvent(QMouseEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::mouseMoveEvent(QMouseEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::mousePressEvent(QMouseEvent *event) {
std::cout << __PRETTY_FUNCTION__ << " ";
//どのボタンのイベントかを出力
//button() 関数 は,QMouseEvent クラスの基底クラス QSinglePointEvent クラスで定義されている.戻り値の型は enum Qt::MouseButton という列挙体.
std::cout << "button " << event->button() << ", ";
//ボタンが押された位置を出力
//position() 関数も QSinglePointEvent クラスで定義されている.戻り値は QPointF クラスのオブジェクト
QPointF point = event->position();
std::cout << "x " << point.x() << ", ";
std::cout << "y " << point.y() << std::endl;
}
void D3_Window::mouseReleaseEvent(QMouseEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::moveEvent(QMoveEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::paintEvent(QPaintEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::resizeEvent(QResizeEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::showEvent(QShowEvent *event) {
//基底クラスのハンドラを呼び出さないと,ウィンドウの下(デスクトップとか他のウィンドウとか)が描画されてしまう
Qt3DExtras::Qt3DWindow::showEvent(event);
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::tabletEvent(QTabletEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void D3_Window::wheelEvent(QWheelEvent *event) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
draw_obj.h
描画用のウィンドウ DrawWindow は,D3_Window クラスのインスタンスに変更しています.
#ifndef ___DRAW_OBJ
#define ___DRAW_OBJ
#include "d3_window.h"
class Draw_Obj : public QObject {
private:
D3_Window *DrawWindow;
public:
Draw_Obj();
~Draw_Obj() {}
D3_Window *get_draw_window()
{ return DrawWindow; }
void init();
};
#endif
draw_obj.cc
#include "draw_obj.h"
Draw_Obj::Draw_Obj()
: DrawWindow(nullptr)
{
DrawWindow = new D3_Window();
}
void Draw_Obj::init() {
if(DrawWindow) {
delete DrawWindow;
DrawWindow = new D3_Window();
}
}
main_window.h
#include <QMainWindow>
#include <QMenuBar>
#include <QHBoxLayout>
#include "draw_obj.h"
class Main_Window : public QMainWindow {
private:
Q_OBJECT
QMenuBar *menu_bar;
QMenu *file_menu;
QAction *action_quit;
QHBoxLayout *CentralLayout;
QWidget *Container;
Draw_Obj DrawObj;
D3_Window *DrawWindow;
public:
Main_Window(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
};
main_window.cc
#include "main_window.h"
Main_Window::Main_Window(QWidget *parent, Qt::WindowFlags f)
: QMainWindow(parent, f),
menu_bar(menuBar()),
CentralLayout(nullptr),
Container(nullptr),
DrawWindow(nullptr)
{
file_menu = new QMenu("ファイル(&F)", this);
menu_bar->addMenu(file_menu);
action_quit = new QAction("終了(&Q)", this);
file_menu->addAction(action_quit);
connect(action_quit, SIGNAL(triggered()), this, SLOT(close()));
QWidget *central_widget = new QWidget(this);
setCentralWidget(central_widget);
CentralLayout = new QHBoxLayout(central_widget);
DrawWindow = DrawObj.get_draw_window();
Container = createWindowContainer(DrawWindow);
CentralLayout->addWidget(Container);
QSize screenSize = screen()->size();
setMaximumSize(screenSize);
setMinimumWidth(600);
setMinimumHeight(600);
}
main.cc
#include <QMainWindow>
#include <QApplication>
#include "main_window.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Main_Window window(nullptr, Qt::Window);
window.show();
return app.exec();
}
tmp.pro
qmake のプロジェクトファイルです.名前を変更しても問題ありません.
TEMPLATE = app
TARGET = window
QT += widgets
INCLUDEPATH += .
HEADERS += main_window.h draw_obj.h d3_window.h
SOURCES += main.cc main_window.cc draw_obj.cc d3_window.cc
QT += 3dcore
QT += 3dextras
#QT += 3drender
#QT += 3dinput
ビルドと実行
![Draw_Widget を作成](./qt_event_01.png)
まず Makefile を作成.
~/tmp$ qmake6
次いでビルド.実行ファイル window が生成します.
~/tmp$ make
ビルドに成功したら実行.
~/tmp$ ./window &
とするとウィンドウが表示されます.
以下に,端末への出力をいくつか記します.
起動
ペイントイベントが 2 回発生しています.
virtual void D3_Window::showEvent(QShowEvent*) virtual void D3_Window::resizeEvent(QResizeEvent*) virtual void D3_Window::paintEvent(QPaintEvent*) virtual void D3_Window::paintEvent(QPaintEvent*)
クリック
左 → 右 → ホイールボタンとクリックしてみました.
クリックにより,mousePressEvent と mouseReleaseEvent() が呼び出されました.
マウスボタンには,それぞれ 1,2,4 という番号が割り当てられていることが判りました.
virtual void D3_Window::mousePressEvent(QMouseEvent*) button 1, x 392, y 353 virtual void D3_Window::mouseReleaseEvent(QMouseEvent*) virtual void D3_Window::mousePressEvent(QMouseEvent*) button 2, x 392, y 353 virtual void D3_Window::mouseReleaseEvent(QMouseEvent*) virtual void D3_Window::mousePressEvent(QMouseEvent*) button 4, x 392, y 353 virtual void D3_Window::mouseReleaseEvent(QMouseEvent*)
ダブルクリック
マウスを押して,離して,押した時点で,ダブルクリックかシングルクリックが 2 回かが判断されることが判ります.
virtual void D3_Window::mousePressEvent(QMouseEvent*) button 1, x 512, y 269 virtual void D3_Window::mouseReleaseEvent(QMouseEvent*) virtual void D3_Window::mousePressEvent(QMouseEvent*) button 1, x 512, y 269 virtual void D3_Window::mouseDoubleClickEvent(QMouseEvent*) virtual void D3_Window::mouseReleaseEvent(QMouseEvent*)
終了
virtual void D3_Window::hideEvent(QHideEvent*)
参考書の検索
- Amazon の「コンピュータ・IT」本カテゴリーでの,「Qt」での検索結果です
- Amazon の「コンピュータ・IT」本カテゴリーでの,「C++」での検索結果です