Qt6のUIプログラムでHelloWorldするためのメモ
まずQt CreatorのインストールはVoid Linuxだとインストーラーが起動して最初の画面でinvalid dataというメッセージが表示され、うまくいきませんでした。
同じvoid linuxを使っている海外の人も同じ現象で解決できてないっぽいので、深追いはせず、違うOSでインストールしました。Arch Linuxのi3環境でインストールできました。
Qt Creatorのインストール方法
・公式サイトからオープンソース版をダウンロード。
・ダウンロードした.runファイルに実行権限を与え、ファイルを実行するとインストーラーが立ち上がります。
$ cd Download/
$ chmod +x <ダウンロードしたファイル名>.run
S ./<ダウンロードしたファイル名>.run
・インストーラ画面でメールアドレスとパスワードを登録しインストールへと進む。必要なパッケージを選択してインストール。
以上でインストールが完了します。
非デスクトップ環境でのQt Creatorの起動方法
Arch Linuxのi3環境なので、GUIでアプリをダブルクリックとかできないので、ターミナルから実行します。
どのファイルを実行したらQt Creatorが起動できるのかわからず、結構ハマりました。
Qt Creatorの起動は下記のディレクトリのファイルを実行することで起動できます。
まず、インストールをホームディレクトリにした場合、~/Qtが全体のアプリが入っているディレクトリとなり、qtcreatorというファイルを実行すればいいのですが、それは下記のパスになります。
~/Qt/Tools/QtCreator/bin/qtcreator
上記のファイルを実行します。現在homeディレクトリにいる場合を想定。
[hoge@amaenbo ~]$ ./Qt/Tools/QtCreator/bin/qtcreator
これでQt Creatorが起動されます。
※毎回この1行を入力するのはめんどくさいので、いいかげんめんどくさくなってきたら、もっとかんたんに起動するように対策する感じでいこうと思います。
Qt6でHelloWorldしてみたので手順をメモ
OS: Serene Linux (Fedora)
※LinuxならどのOSでも手順は変わらないです。
UIをつくるための選択肢としてQt quick とQt Widgetがある。
Qt widgetは昔からあり、Qt quickは新しめのシステムでスマホ対応もできる。
Qt Widgetをまずは使ってみたほうが良さそうなので、Qt Widget→Qt quickの順に操作を覚えたらいいかも。
Hello Worldの手順
Qt WidgetでHello Worldします。
<Welcome>→<Projects>→<+new>→<Qt Widgets Application>を選択
Project Location
・プロジェクト名を入力
適当なプロジェクト名を入力する。
・プロジェクトを生成するディレクトリを入力
$HOMEディレクトリにしました。プロジェクトを何個かつくるだけでもホームディレクトリが散らかるので、ホームディレクトリにQtのプロジェクト専用のディレクトリを作ってその中に入れたほうがいいかも。
Define Build System
・Build Systemを選択
qmakeを選択
Class Information
・Base classはQWidgetを選択
・Generate formのチェックボックスのチェックを外す
Translation File
・noneのまま次へ
Kit Selection
・Desktop Qt 6.0.1 GCC 64bitを選択
Project Management
・noneのままでfinishを押下
以上でHello Worldのためのプロジェクトディレクトリとソースファイルが指定したディレクトリに生成されます。
生成されたプロジェクトのディレクトリとファイル構成
ディレクトリとファイルが自動生成され、ファイルにはスケルトンコードが書かれています。
・Headers/widget.h
ヘッダーファイル
・Sources/widget.cpp
widget.hの実装ファイル
・Sources/main.cpp
アプリのメインファイル
・<プロジェクト名>.pro
proファイルは、このファイルに書かれた設定内容を元にしてqmakeがビルドするためのファイル。
qmakeとは
自動でビルドするツールのこと。CMakeなどのビルドツールと似ているけど、qmakeはQtのために作られたビルドツール。
プロジェクトを作成した時点でスケルトンコードのファイルが生成され、Qt CreatorのRunボタンを押すなどすると、Hello Worldと書かれたアプリのブランクウィンドウが表示されます。
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
UIプログラミングの作法として、QApplicationのインスタンスを作成し処理の最後にQApplicationのインスタンスをexec()する。
QApplication aによってQApplicationのインスタンスaを生成
return a.exec();することで、exec()内でイベントループが起動されてOSやアプリケーションのイベントを受け取って処理が行えるようになる。
GUIのアプリケーションは、ボタンをクリックしたら文字を表示するなど、何らかのイベントを検知して、そのイベントに対応した処理を行うのでイベントループを起動している。
widget w; でQwidgetを継承したwidgetクラスのインスタンスを作成。
widgetクラスのメンバ関数show()を実行することで作成するアプリのウィンドウが表示される。
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
}
Widget::~Widget()
{
}
Hello Worldを表示するためにコードを追加
現時点ではウィンドウになにも表示されないので、main.cppにコードを追加してウィンドウにHello Worldを表示する。
main.cpp
#include "widget.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
new QPushButton("Hello World", &w); // 追加
w.show();
return a.exec();
}
new QPushButton("Hello World", &w);
を追加することでボタンの中にHello Worldと表示された。
このQPushButtonオブジェクトの第二引数にWidgetのポインタを渡していることで、WidgetとQPushButtonオブジェクトに親子関係ができる。Widgetが親で、QPushButtonが子。
Widgetオブジェクトであるウィンドウの中に、QPushButtonであるHello Worldと書かれたオブジェクトが入れられるようになり、画像のように表示される。
ここでの親子関係は親クラスと子クラスとは別物なので注意。
ここでの親子関係はHTMLの要素みたいな親要素と子要素の関係と同じとイメージでいいかも。
HTMLみたいに、親であるWidgetのウィンドウがQPushButtonウィジェットのサイズに合わせて調整されたので、ウィンドウがちっちゃくなっている。
また、new QPushButton("Hello World", &w);
でnewしてメモリを確保しているのに、deleteでメモリを開放していないけど、自動的にメモリが開放される仕組みとなっているので、自分でdeleteしなくてもいい。
理由は、第二引数にQPushButtonの親としてwidgetインスタンスのアドレスを渡しているから。
親であるwidgetインスタンスの方で自動的にdeleteされるようになっているので、親の中に存在する子のQPushButtonも一緒にdeleteされる機能が組み込まれている。
このメモリ管理の機能は、QObjectの派生クラスなら使用できる。widgetクラスもQPushButtonクラスも派生クラス。
Widgetのウィンドウサイズを調整する
Widgetクラスのウィンドウサイズの調整をするため、Widget.hに関数を追加する。
widget.hのclass WidgetのWidgetの上にカーソルをあて、右クリック。
Refactor→Insert Vurtual Functions of Base Class→QWidgetカテゴリのsizeHint() const: Qsizeのチェックボックスにチェックを入れる。
Insert definitions in implementation file(実装ファイルに定義を追加)を選択し、Add "override" equivalent to function declaration(関数宣言にオーバーライド修飾子を追加)にチェックを入れoverrideを選択。
Insert definitions in implementation file(実装ファイルに定義を追加)を選択することで、実装ファイル、ここではwidget.cppに関数の定義が追加されるので手で書くよりも正確で便利。
最後に右下のokボタンを押すと、widget.hとwidget.cppに下記のように関数が追加される。
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
// 追加start
// QPaintDevice interface
public:
QPaintEngine *paintEngine() const override;
// QWidget interface
public:
QSize sizeHint() const override;
// 追加end
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
}
Widget::~Widget()
{
}
// 追加start
QPaintEngine *Widget::paintEngine() const
{
}
QSize Widget::sizeHint() const
{
}
// 追加end
sizeHint()関数の中にQSize()関数を追加することで、指定したウィンドウサイズが適用される。
QSize Widget::sizeHint() const
{
// 追加
return QSize(400,300);
}
実行すると、下記のように表示される。
HTMLでいうと一番外側にあるブロック要素(div要素など)みたいに親がいない場合、div要素がウィンドウの枠になるのと一緒で、親がいないQWidgetのことをトップレベルウィジェットと呼び、トップレベルウィジェットがウィンドウとして表示される(show()を使うことで表示される)。
トップレベルウィジェットが何個もある場合、トップレベルウィジェットごとにshow()することで、トップレベルウィジェットが表示される。
main.cpp
#include "widget.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w1;
new QPushButton("Hello World", &w1);
w1.show();
Widget w2;
new QPushButton("Hello Qt", &w2);
w2.move(w1.x(), w1.y() + 200);
w2.show();
return a.exec();
}
Qt Creatorの機能など
エディタのコードにリアルタイムでエラーやワーニングを表示されているが、これはQt Creatoのデフォルトの機能で、c++のClangと呼ばれるコンパイラフロントエンドの機能。
ビルドをしなくてもコードを書いた時点でエラー箇所など表示して知らせてくれるので便利。エラー解消したら消えます。
リファクタリングがラク
インクルードせずにいきなりmain関数の中に使いたいメソッドを書いて、右クリックからリファクタリングを選択しインクルードを選択すると、インクルードの宣言を自動で追加してくれる。
ヘッダーファイルにプロトタイプ宣言を自分で書いたあと、実体をまだ書いていない状態で、上と同じく右クリックからのメニューでcppファイルに実体を追加してくれる。
mkmkm