Submit Search
QtとC++でGUIプログラミング
•
55 likes
•
57,818 views
S
seanchas_t
Follow
C++勉強会 @ tkb #2 での発表資料
Read less
Read more
1 of 56
Download now
Downloaded 103 times
More Related Content
QtとC++でGUIプログラミング
1.
QtとC++で GUIプログラミング @seanchas_t 2013年9月28日 13年9月29日日曜日
2.
自己紹介 • twitter.com/seanchas_t • [PR]
Qtでペイントソフトを制作中 - github.com/iofg2100/PaintField 13年9月29日日曜日
3.
イントロダクション 13年9月29日日曜日
4.
はじめに • C++でGUIアプリを作ろう • 今回紹介するのは Qtを使ったGUIアプリ開発 -
コード例、Qtのシステムの概略の紹介 13年9月29日日曜日
5.
目次 • イントロダクション • 使ってみる
(Qt Widgets編) • 使ってみる (Qt Quick編) • QObjectについて • Qtのコンテナライブラリ • Qtの描画システム 13年9月29日日曜日
6.
Qtについて • クロスプラットフォームのアプリケーション、UIフ レームワーク - WindowsでもMacでもLinuxでも 同じコードが動く -
Android、iOSにもQt 5.1から実験的に対応 - 今回はデスクトップに限った話 13年9月29日日曜日
7.
Getting Started • qt-project.org/downloads からダウンロード -
もしくはお好きなパッケージマネージャで • 統合開発環境はQt Creator • C++11を使う場合は、 プロジェクトファイル (*.pro) に “CONFIG += c++11” を追加 13年9月29日日曜日
8.
使ってみる (Qt Widgets編) 13年9月29日日曜日
9.
Qt Widgetsとは • Qtに昔からある、GUIの記述方法 •
C++で各UI部品を作って配置 13年9月29日日曜日
10.
• ボタンを押したら数字が1増える シンプルなカウンタを作ろう こんな感じ ボタン ラベル 13年9月29日日曜日
11.
シンプルなカウンタを作ろう カウンタ イメージ図 ボタン ラベル クリック カウントアップ 値が変化 文字列を更新
↓UI 13年9月29日日曜日
12.
シンプルなカウンタを作ろう • Qtでは「シグナル」と「スロット」 を使ってこの図と同じようにコードを組む 13年9月29日日曜日
13.
カウンタ class Counter :
public QObject { Q_OBJECT public: explicit Counter(QObject *parent = 0) : QObject(parent) {} signals: void countChanged(int count); public slots: void increment() { ++m_count; emit countChanged(m_count); } private: int m_count = 0; }; 13年9月29日日曜日
14.
カウンタ class Counter :
public QObject { Q_OBJECT public: explicit Counter(QObject *parent = 0) : QObject(parent) {} signals: void countChanged(int count); public slots: void increment() { ++m_count; emit countChanged(m_count); } private: int m_count = 0; }; このオブジェクトが 発することのできる「シグナル」 (値が変化したことを知らせる) 13年9月29日日曜日
15.
カウンタ class Counter :
public QObject { Q_OBJECT public: explicit Counter(QObject *parent = 0) : QObject(parent) {} signals: void countChanged(int count); public slots: void increment() { ++m_count; emit countChanged(m_count); } private: int m_count = 0; }; シグナルに呼応して 実行される「スロット」 (カウントアップ) 13年9月29日日曜日
16.
トップレベルのウィジェット class Widget :
public QWidget { Q_OBJECT public: explicit Widget(Counter *counter, QWidget *parent = 0) : QWidget(parent) { auto layout = new QVBoxLayout(); auto label = new QLabel("0"); connect(counter, SIGNAL(countChanged(int)), label, SLOT(setNum(int))); layout->addWidget(label); auto button = new QPushButton("Increment"); connect(button, SIGNAL(pressed()), counter, SLOT(increment())); layout->addWidget(button); setLayout(layout); } }; 13年9月29日日曜日
17.
トップレベルのウィジェット class Widget :
public QWidget { Q_OBJECT public: explicit Widget(Counter *counter, QWidget *parent = 0) : QWidget(parent) { auto layout = new QVBoxLayout(); auto label = new QLabel("0"); connect(counter, SIGNAL(countChanged(int)), label, SLOT(setNum(int))); layout->addWidget(label); auto button = new QPushButton("Increment"); connect(button, SIGNAL(pressed()), counter, SLOT(increment())); layout->addWidget(button); setLayout(layout); } }; レイアウトで ボタンやラベルを配置 13年9月29日日曜日
18.
トップレベルのウィジェット class Widget :
public QWidget { Q_OBJECT public: explicit Widget(Counter *counter, QWidget *parent = 0) : QWidget(parent) { auto layout = new QVBoxLayout(); auto label = new QLabel("0"); connect(counter, SIGNAL(countChanged(int)), label, SLOT(setNum(int))); layout->addWidget(label); auto button = new QPushButton("Increment"); connect(button, SIGNAL(pressed()), counter, SLOT(increment())); layout->addWidget(button); setLayout(layout); } }; 先ほどのCounterと、 ボタン・ラベルのシグナル/スロットを接続 13年9月29日日曜日
19.
main関数 int main(int argc,
char *argv[]) { QApplication app(argc, argv); Counter counter; Widget widget(&counter); widget.show(); return app.exec(); } 結局こんな感じになる (先ほどと同じ) 13年9月29日日曜日
20.
使ってみる (Qt Quick編) 13年9月29日日曜日
21.
Qt Quickとは • QMLという言語を使ってUIを記述 •
QMLは動的にロードされる • CSSっぽくオブジェクトを配置、 プロパティを設定 • JavaScriptでロジックも記述可能 - JavaScriptでは無理なことも • ローカルファイルへのアクセスとか 13年9月29日日曜日
22.
Qt Quickとは • C++との連携も可能 -
QMLからC++を呼び出す - C++からQMLを呼び出す - Qt QuickのUIアイテムをC++で実装する • C++だとQQuickItem 13年9月29日日曜日
23.
カウンタ class Counter :
public QObject { Q_OBJECT public: explicit Counter(QObject *parent = 0) : QObject(parent) {} Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged) int count() const { return m_count; } void setCount(int count) { m_count = count; } signals: void countChanged(int count); public slots: void increment() { ++m_count; emit countChanged(m_count); } private: int m_count = 0; }; 13年9月29日日曜日
24.
カウンタ class Counter :
public QObject { Q_OBJECT public: explicit Counter(QObject *parent = 0) : QObject(parent) {} Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged) int count() const { return m_count; } void setCount(int count) { m_count = count; } signals: void countChanged(int count); public slots: void increment() { ++m_count; emit countChanged(m_count); } private: int m_count = 0; }; setter、getter、変更時のsignalを登録して プロパティを宣言 13年9月29日日曜日
25.
QML import QtQuick 2.1 import
QtQuick.Controls 1.0 ApplicationWindow { title: "Window" Column { anchors.fill: parent anchors.margins: 10 spacing: 10 Label { text: counter.count } Button { text: "Button" onClicked: { counter.increment() } } } } 13年9月29日日曜日
26.
QML import QtQuick 2.1 import
QtQuick.Controls 1.0 ApplicationWindow { title: "Window" Column { anchors.fill: parent anchors.margins: 10 spacing: 10 Label { text: counter.count } Button { text: "Button" onClicked: { counter.increment() } } } } Qt Quick Controls 以前のQt Quickにはなかったボタン、メニューなどの よく使うGUI部品などが使えるようになった (5.1から) 13年9月29日日曜日
27.
QML import QtQuick 2.1 import
QtQuick.Controls 1.0 ApplicationWindow { title: "Window" Column { anchors.fill: parent anchors.margins: 10 spacing: 10 Label { text: counter.count } Button { text: "Button" onClicked: { counter.increment() } } } } C++で書いたCounterオブジェクトを使用可能 13年9月29日日曜日
28.
QML import QtQuick 2.1 import
QtQuick.Controls 1.0 ApplicationWindow { title: "Window" Column { anchors.fill: parent anchors.margins: 10 spacing: 10 Label { text: counter.count } Button { text: "Button" onClicked: { counter.increment() } } } } プロパティバインディング 13年9月29日日曜日
29.
プロパティバインディング • プロパティに他のオブジェクトの プロパティを使った式を使うと、 自動的にその変化に追従させられる • Reactive
Programming - Excelっぽい • QMLの大きな特徴 13年9月29日日曜日
30.
QML import QtQuick 2.1 import
QtQuick.Controls 1.0 ApplicationWindow { title: "Window" Column { anchors.fill: parent anchors.margins: 10 spacing: 10 Label { text: counter.count } Button { text: "Button" onClicked: { counter.increment() } } } } プロパティバインディング textが、counterのcountプロパティ (先ほど宣言した)に追従 13年9月29日日曜日
31.
QML import QtQuick 2.1 import
QtQuick.Controls 1.0 ApplicationWindow { title: "Window" Column { anchors.fill: parent anchors.margins: 10 spacing: 10 Label { text: counter.count } Button { text: "Button" onClicked: { counter.increment() } } } } JavaScriptで処理を書ける (カウンタのインクリメント) 13年9月29日日曜日
32.
main関数 int main(int argc,
char *argv[]) { QApplication a(argc, argv); QQmlApplicationEngine engine(QUrl("qrc:/main.qml")); Counter counter; engine.rootContext()->setContextProperty("counter", &counter); auto window = qobject_cast<QQuickWindow *>(engine.rootObjects().first()); window->show(); return a.exec(); } 13年9月29日日曜日
33.
main関数 int main(int argc,
char *argv[]) { QApplication a(argc, argv); QQmlApplicationEngine engine(QUrl("qrc:/main.qml")); Counter counter; engine.rootContext()->setContextProperty("counter", &counter); auto window = qobject_cast<QQuickWindow *>(engine.rootObjects().first()); window->show(); return a.exec(); } counterをQML内で使えるようにする 13年9月29日日曜日
34.
main関数 int main(int argc,
char *argv[]) { QApplication a(argc, argv); QQmlApplicationEngine engine(QUrl("qrc:/main.qml")); Counter counter; engine.rootContext()->setContextProperty("counter", &counter); auto window = qobject_cast<QQuickWindow *>(engine.rootObjects().first()); window->show(); return a.exec(); } ApplicationWindow(C++ではQQuickWindowに相当) を参照して表示させる 13年9月29日日曜日
35.
QObject 13年9月29日日曜日
36.
QObjectとは • 普通のC++にはないQtの様々な機能 - signal・slot -
QMLからの メソッドの動的な呼び出し QObjectの機能 13年9月29日日曜日
37.
QObjectとは • QWidget系のオブジェクトも QMLのオブジェクトも 全部QObjectから派生している • 先ほど作ったCounterクラスもQObjectから派生 13年9月29日日曜日
38.
QObjectの例 (さっきの) class Counter
: public QObject { Q_OBJECT public: explicit Counter(QObject *parent = 0) : QObject(parent) {} Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged) int count() const { return m_count; } void setCount(int count) { m_count = count; } signals: void countChanged(int count); public slots: void increment() { ++m_count; emit countChanged(m_count); } private: int m_count = 0; }; signal・slot プロパティ 13年9月29日日曜日
39.
QObjectの機能 • 親子構造 • シグナルとスロット •
プロパティ • リフレクション - 動的なメソッドの呼び出し - 動的なプロパティの書き換え • など 13年9月29日日曜日
40.
QObjectの機能 • なぜこんなことができるのか? - Meta-Object
Compiler (MOC) の活躍 - ビルド時にヘッダファイルを読み込んで 各クラスごとに特殊なコードを生成 - Q_OBJECTマクロが必要 13年9月29日日曜日
41.
QObjectの親子構造 • QObjectは親子構造を持つことができる • 親がdeleteされると子もdelete -
わざわざ手動でdeleteする必要がない • QObjectのメモリ管理は この親子関係で行われる 13年9月29日日曜日
42.
QObjectの親子構造 auto parent =
new QObject(); auto child1 = new QObject(parent); auto child2 = new QObject(); child2->setParent(parent); delete parent; child1, child2も自動的にdeleteされる 13年9月29日日曜日
43.
シグナルとスロット • signalを発すると、そのsignalに接続された すべてのslotが呼び出される • QObject::connectで接続 •
類似のライブラリ: Boost.Signals2 • スレッド間でも使える (イベントとしてキューされる) 13年9月29日日曜日
44.
シグナルとスロット auto lineEdit =
new QLineEdit(); auto label = new QLabel(); connect(lineEdit, SIGNAL(textChanged(QString)), label, SLOT(setText(QString))); connect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText); connect(lineEdit, &QLineEdit::textChanged, [](const QString &text){ qDebug() << "text changed to" << text; }); 従来の方法。SIGNALとSLOTは実は文字列を返すマクロ メンバ関数ポインタで接続 (Qt5から) 任意の関数オブジェクトを接続 (Qt5から) 13年9月29日日曜日
45.
動的なメソッドの呼び出し • signalや、Q_INVOKABLEを付けたメソッドは 動的に呼び出すことができる • QMLからでも呼び出せるようになる 13年9月29日日曜日
46.
動的なメソッドの呼び出し class Object :
public QObject { Q_OBJECT public: explicit Object(QObject *parent = 0); void method1(); Q_INVOKABLE void method2(); public slots: void slot1(); }; NG OK 13年9月29日日曜日
47.
Qtのコンテナライブラリ 13年9月29日日曜日
48.
Qtのコンテナライブラリ • Qtには、様々な独自のコンテナライブラリが 用意されている - QString
(文字列) - QList (リスト) - QHash (辞書) - など 13年9月29日日曜日
49.
Qtのコンテナライブラリ • STLとの違い - メソッドが豊富 -
コピーオンライトである • コンテナをコピーしても、変更が加わるまでは 同じ内部データを共有する • shared_ptrとかmove semanticsとか 考えなくてもいい - 総じてSTLより易しい 13年9月29日日曜日
50.
Qtのコンテナライブラリ • STLとの互換性 - begin()、end()などは用意されている •
range-based forでも使える • STLのアルゴリズムが使える - QList、QHashではinitializer_listも使える 13年9月29日日曜日
51.
Qtの描画システム 13年9月29日日曜日
52.
描画システム (Qt Widgets) •
描画イベントが発生すると QWidget::paintEventが呼ばれる • QWidget::paintEvent内で実際に描画 class Widget : public QWidget { ... protected: void paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBrush(Qt::red); painter.drawEllipse(0, 0, 100, 100); } }; 13年9月29日日曜日
53.
描画システム (Qt Quick) •
scene graph (描画する図形や変形などを木構造で表したグラフ) を構築して描画が行われる • scene graphの更新時、各Itemごとに、 QQuickItem::updatePaintNodeが呼ばれる • scene graphはメインとは別のスレッドで描画される • (QQuickPaintedItemを継承して QWidget風の描画方法も一応可能) 13年9月29日日曜日
54.
描画システム (Qt Quick) class
Item : public QQuickItem { Q_OBJECT public: explicit Item(QQuickItem *parent = 0) : QQuickItem(parent) { this->setFlag(ItemHasContents, true); } protected: QSGNode *updatePaintNode(QSGNode *old, UpdatePaintNodeData *) { auto node = static_cast<QSGSimpleRectNode *>(old); if (!node) { node = new QSGSimpleRectNode(); node->setColor(Qt::red); } node->setRect(this->boundingRect()); return node; } }; 13年9月29日日曜日
55.
まとめ • Qtの簡単な使用例と概要について紹介 • C++の応用の参考の1つになれば幸い 13年9月29日日曜日
56.
以上です 13年9月29日日曜日
Download