Qt 5.4 ことはじめ #1

Qt (キュート)1 を触り始めました。 Qt を使ってデスクトップで動く GUI アプリケーションを作っていきます。 その過程で得たことを備忘録として残しておきます。

今回取り扱う環境は、OS X と Xcode, Qt 5.4 です。また Qt のインストール先を ~/Qt にしています。 Qt 自体はクロスプラットフォームな開発環境になっているので、お使いの開発環境に合わせて適宜読み替えてください。

Note: こうしたツールやフレームワークの使い方について日記をつけても、 バージョンが上がり提供される API や機能が変わると、 あっという間に内容が古くなり、役に立たなくなることがしばしばあります。 とはいえ、文献はあるに越したことはありません。 Qt に限らず、ちょっとした備忘録を今後もこまめに残していこうと思います。

Qt 5.4 を手に入れる

まず手始めに、Qt を手に入れます。 Qt Community をこのページからダウンロードします。 オンラインインストーラになっているのでぽちぽちクリックしてお好きな場所にインストールします。 インストールにざっと 30 分ほどかかるので、コーヒーでも飲んでお待ちください。

qmake のパスを通す

インストールしたら、qmake のパスを通しておきます。 僕の環境は OS X と zsh を使っているので、次のような alias を .zshrc に追加しました。

alias qmake="~/Qt/5.4/clang_64/bin/qmake"

次のようにパスを通してもいいと思います:

export QT_SDK_ROOT=~/Qt/5.4
export PATH=$PATH:$QT_SDK_ROOT/clang_64/bin

ターミナル上で where qmake もしくは qmake -v と打ち、パスが通ってるか確認しておきましょう。

> qmake -v
QMake version 3.0
Using Qt version 5.4.1 in ~/Qt/5.4/clang_64/lib

qmake を使って Xcode のプロジェクトファイルを生成する

Xcode のプロジェクトファイル (.xcodeproj) を作るには、Qt プロジェクトのディレクトリで次のコマンドを実行します。

qmake -spec macx-xcode

Qt 5.4 の Xcode でのプリプロセス

qmake で生成された Xcode プロジェクトで、ビルドすると次のプリプロセス (Qt Preprocess) がまず走ります。

make -C /path/to/MyApp -f MyApp.xcodeproj/qt_makeqmake.mak
make -C /path/to/MyApp -f MyApp.xcodeproj/qt_preprocess.mak

これによって、Qt 特有の signal などの記述を、C++ にバインディングしてるようです。 例えば、QObject を継承した MyClass を定義します。 すると MyClass.hMyClass.cpp から moc_MyClass.cpp がプリプロセスによって生成されます。

音楽を再生する

Qt プロジェクトファイル(例 MyApp.pro)に依存するフレームワークとして multimedia を追加します。

QT += multimedia

他に qml, quick, widgets に依存している場合は、このように追加します:

QT += qml quick widgets multimedia

音楽を再生する場合は、QMediaPlayer を使います。 QMediaPlayer::setMedia では再生する音楽の URL を QUrl で指定することになります。 ローカルに置いてる音楽ファイルはもちろん、インターネット上の音楽ファイルも再生することができるようです。 簡単のため、QObject を継承した MyClass のコンストラクタに記述しました。

#include "MyClass.h"
#include <QMediaPlayer>

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    QUrl url = QUrl("http://a898.phobos.apple.com/us/r1000/039/Music6/v4/"
      "13/22/67/1322678b-e40d-fb4d-8d9b-3268fe03b000/"
      "mzaf_8818596367816221008.plus.aac.p.m4a");

    QMediaPlayer* player = new QMediaPlayer(this, QMediaPlayer::StreamPlayback);
    player->setMedia(url);
    player->setVolume(70);
    player->play();
}

ListView にスクロールバーを追加する

QML で ListView にスクロールバーを表示する場合は、ListViewScrollView の中に入れます。

ScrollView {
  ListView {
    // ...
  }
}

ウィンドウのタイトルバーを非表示にする

ウィンドウのタイトルバーを非表示にする場合は、QML で ApplicationWindow.flagsQt.FramelessWindowHint を設定します。

ApplicationWindow {
  flags:Qt.FramelessWindowHint
}

QML で GUI のイベントを受け取る

TextFieldonEditingFinished イベントが発生したときにそのテキストの内容ををデバッグログに表示します。 OS X だとこのイベントは、テキストを入力後 Enter キーを押したときに発生します。

TextField {
  onEditingFinished: console.log(this.text)
}

キーボードのイベントを受け取るときは Keys を使います。

TextField {
  Keys.onReleased: console.log("onReleased")
}

スコープを使って、イベントを受け取ったときの処理(シグナルハンドラー)も書けます。

TextField {
  Keys.onPressed: {
      if (event.key === Qt.Key_Down) {
        console.log("onPressed: Key_Down");
      }
  }
}

console.log の記述をみて、お気付きになった方も多いかもしれません。 QML では、JavaScript でプログラミングロジックを書くことができます。

NOTE: event.key === Qt.Key_Down のようにここでは == 演算子ではなく、=== 演算子を使っています。 試しに、== 演算子を使って比較すると、Qt Designerで警告 (M126) が表示されます。 これは == を使って比較するときに、2つの型が異なると強制的に型変換が行われるためです。 予期しない動作を防ぐため、代わりに === 演算子を使いましょう。 こういったところも JavaScript です。

Qt でデバッグプリント

C++ の場合は qDebug 関数を使ってデバッグプリントができます。

#include <QDebug>

void MyClass::onText(const QString& in)
{
  qDebug() << in;
  qDebug("ok");
}

QML の場合 console.log が使えるようです。

Rectangle {
  Keys.onPressed: {
      if (event.key === Qt.Key_Down) {
        console.log("key down");
      }
  }
  Keys.onReleased: console.log("released")
}

QML から QObject (C++) の関数を呼び出す

QQmlApplicationEngine::rootContextQQmlContext を取得して、 QQmlContext::setContextPropertyQObject を設定する形になります。 余談ですが、コンテキストにオブジェクトのポインタを設定するところは JavaScriptCore や V8, Lua などのスクリプトエンジンのバインディングと似ていますね。 例を載せておきます。

main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "MyClass.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    MyClass myClass;
    engine.rootContext()->setContextProperty(QStringLiteral("myClass"), &myClass);

    return app.exec();
}

MyClass.h:

#include <QObject>

class MyClass : public QObject {
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0);
    ~MyClass();

    Q_INVOKABLE void onEditingFinished(const QString& text);
};

QML では QQmlContext::setContextProperty に設定したオブジェクト名 (myClass) を使って、C++ の関数を呼び出すことができます。

TextField {
  onEditingFinished: myClass.onEditingFinished(this.text)
}

参考文献


  1. 発音は "cute" (キュート)が一般的だそうですが、"CUE-TEE" あるいは "Q-T" (キューティー)という発音ももちろん通じるそうです。 

Leave a Reply