はじめに

昨日は @task_jp さんによる QtWebService の紹介 でした。もともと QtQuick と呼ばれる GUI/HMI の技術のために開発された QML という言語が、まったく関係ないウェブの世界でも便利に活用されていてとても興味深いですね。

本日は Qt Creator の機能を2つほど紹介しようと思います。

スニペット機能

image.png

Qt Creator で cla とか Q_PROP とか打つと出てくる補完リストの中に image.png 赤い丸 がついているやつが「スニペット」と呼ばれる機能です。
キーワードに関連したコードの雛形を展開することができる素晴らしい機能で、たまに役に立ったり、たまにイライラさせてくれるやつです。

スニペットの一覧

Qt Creator の設定の「Text Editor」の「Snippets」に一覧があります。

image.png

Group: のところでグループ(言語や形式)を切り替えることができますが、今回は C++ のものをいくつか見てみましょう。

class

class
class $name$
{
public:
    $name$() {}
};

$name$ となっているところが変数になっていて、コードエディタでスニペットを選択して確定すると以下のように編集状態になります。

image.png

ここで class の直後の name を書き換えることで、同じ $name$ となっているコンストラクタ名も同時に書き換わる仕組みになっています。

「クラス名は大文字ではじめたい派」のみなさん、「コンストラクタの実装は宣言部には書かない派」のみなさん、「デストラクタも普通は書くよね」派のみなさんはこの class のスニペットを以下のように書き換えてはいかがでしょうか?

class
class $Name$
{
public:
    $Name$();
    ~$Name$();
};

class derived from QObject

こちらは QObject の派生クラス用のスニペットになります。

class
class $name$ : public QObject
{
    Q_OBJECT
public:
    $name$() {}
    virtual ~$name$() {}
};

「QObject のサブクラスのコンストラクタは explicit で parent 指定するよね派」のみなさんや「ちゃんとコピー禁止にしたいよね」は以下のように書き換えてはいかがでしょう?

class
class $Name$ : public QObject
{
    Q_OBJECT
public:
    explicit $Name$(QObject *parent = nullptr);
    virtual ~$Name$();

private:
    Q_DISABLE_COPY($Name$);
};

class template

次はテンプレートクラスのスニペットです。

class
template <typename $T$>
class $name$
{
public:
    $name$() {}
};

ここでは $T$$name$2つの変数が存在しています。
最初に T の部分を編集し、次の name の編集に移るには Tabキー を押してください。

for

for 文にもスニペットが用意されています。

for
for (int $var$ = 0; $var$ < $total$; ++$var$) {
    $$
}

ループ変数 var と終了値 total の二つの変数に続き $$ という記述が登場しました。ご想像のとおり、変数(名)の設定が済んだ後に Return キー を押すとこの場所にカーソルが移動し、ループの中の処理の記述がすぐにはじめられるようになっています。

スニペットの追加

for range based

以前は Qt の foreach をよく使っていたのですが、最近は range based for 形式でコードを記述することが多くなってきました。

というわけで、それ用のスニペットを追加してみましょう。

「Add」ボタンを押して、Trigger には for と、 Trigger Variant には range based などと指定をし、以下のような雛形にします。

for
for ($type$ $elem$ : $container$) {
    $$
}

これで、一つコードの記述が楽になりましたね。

property

Qt のプロパティの実装って単純作業で面倒くさいので(でも MEMBER はイヤ)これもスニペット化するのがおすすめです。

property(value)
$type$ $class$::$name$() const
{
    return d->$name$;
}

void $class$::set$name:c$($type$ $name$)
{
    if (d->$name$ == $name$) return;
    d->$name$ = $name$;
    emit $name$Changed($name$);
}
property(class)
$type$ $class$::$name$() const
{
    return d->$name$;
}

void $class$::set$name:c$(const $type$ &$name$)
{
    if (d->$name$ == $name$) return;
    d->$name$ = $name$;
    emit $name$Changed($name$);
}

プリミティブな型(int とか bool とか)は value の方を、Qt のクラスなどの場合は class の方を使うことを想定しています。

また、ここでメンバ変数が d-> となっているのは、2015年の Advent Calendar で紹介した d-pointer を使うことを前提としているためです。(Private クラスの宣言もスニペット向きですね。)

設定用のメソッドを注意深く見てみると set$name:c$ と変数名の後に :c がついていることが分かると思います。いつも Qt のサブクラスを書いている方であれば容易に想像できると思いますが、これは 変数名の先頭の文字を大文字に変換する というマークになります。

:l をつけると変数名がすべて小文字に、:u をつけるとすべて大文字に変換されます。
前者はクラス名からヘッダファイル名への変換に、後者はクラス名からインクルードガードの変換とかに使えそうですね。

スニペット機能のまとめ

Qt Creator が提供するコード補完の中の1種で雛形を提供する機能がスニペットでした。
割と簡単な仕組みですが工夫次第では日々のコーディングの手間をかなり省いてくれるので、賢く活用しましょう。

詳細は Qt Creator のマニュアルの Adding and Editing Snippets を参照してください。

ウィザード機能

スニペットはちょっとしたコードの雛形のための機能ですが、Qt Creator ではプロジェクトやファイルの雛形も自分で生成することができるようになっています。

デスクトップ向けのアプリケーションについては Qt Creator がデフォルトで提供しているテンプレートでかなりの割合がまかなえるのではないかと思いますが、中規模、大規模な組み込みシステムになってくると独自の拡張を追加した Qt のアプリケーションの雛形が必要になってくるケースがあるので、そういう場合には是非お試しください。

ウィザードの追加に関しては Adding JSON-Based Wizards というとても長いマニュアルがありますので、詳細はこちらを参照してください。

また、Qt Creator 自体が提供しているウィザードのコードが share/qtcreator/templates/wizards/ 以下にありますので、「あのウィザードと同じことがしたいんだけど」という場合はこちらも参考にしてください。

ウィザードの追加

今回は、昨日紹介した QtWebService 向けのウィザードを追加してみようと思います。

wizard.json
{
    "version": 1,
    "supportedProjectTypes": [ "Qt4ProjectManager.Qt4Project" ],
    "id": "U.QtWebServiceApplication",
    "category": "F.Application",
    "trDescription": "Creates a deployable QtWebService application.",
    "trDisplayName": "QtWebService Application",
    "trDisplayCategory": "Application",
    "icon": "webservice.png",
    "featuresRequired": [ "QtSupport.Wizards.FeatureQt.5.3" ],
    "enabled": "%{JS: [ %{Plugins} ].indexOf('QmakeProjectManager') >= 0 }",

    "options":
    [
        { "key": "ProFileName", "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'pro')}" },
        { "key": "MainCppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src')}" }
    ],

    "pages":
    [
        {
            "trDisplayName": "Project Location",
            "trShortTitle": "Location",
            "typeId": "Project"
        },
        {
            "trDisplayName": "Kit Selection",
            "trShortTitle": "Kits",
            "typeId": "Kits",
            "data": {
                "projectFilePath": "%{ProFileName}"
            }
        },
        {
            "trDisplayName": "Project Management",
            "trShortTitle": "Summary",
            "typeId": "Summary"
        }
    ],
    "generators":
    [
        {
            "typeId": "File",
            "data":
            [
                {
                    "source": "app.pro",
                    "target": "%{ProFileName}",
                    "openAsProject": true
                },
                {
                    "source": "main.cpp",
                    "target": "%{MainCppFileName}"
                },
                {
                    "source": "config.qml"
                },
                {
                    "source": "root/index.qml.tpl",
                    "target": "root/index.qml",
                    "openInEditor": true
                },
                {
                    "source": "qml.qrc"
                },
                {
                    "source": "git.ignore",
                    "target": ".gitignore",
                    "condition": "%{JS: !%{IsSubproject} && '%{VersionControl}' === 'G.Git'}"
                }
            ]
        }
    ]
}

QtQuick Application の一番シンプルなテンプレート を参考に、いらないページを削ったり、ファイルのパスの調整をしたりをしたものになります。

app.pro
TEMPLATE = app
QT = webservice

SOURCES += %{MainCppFileName}

RESOURCES += qml.qrc

%{MainCppFileName} のところには main.cpp や設定によっては main.cc が入ります。

main.cpp
%{Cpp:LicenseTemplate}\

#include <QtCore/QCoreApplication>
#include <QtWebService/QWebServiceEngine>

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

    QWebServiceEngine engine(QStringLiteral(":/config.qml"));
    engine.start();

    return app.exec();
}

%{Cpp:LicenseTemplate} が Qt Creator のライセンスの設定の内容にしたがって置換されます。

root/index.qml.tpl
import QtWebService.HTML 5.0

Html {
    Head { title: 'QtWebService' }
    Body {
        H1 { text: 'QtWebService' }
        P { text: '...' }
    }
}

一応テンプレートから qml を生成する形式にしていますが、今のところは設定等はとくにありません。

config.qml
import QtWebService.Config 0.1

Config {
    listen.address: '*'
    listen.port: 8080
    server.name: 'QtWebService'

    contents: {
        '/': './root/',
    }

    cache: {
        'qml': true
    }

    deflate: {
        'video/*': false
        , 'image/*': false
    }
}

QtWebService の設定ファイルです。

qml.qrc
<RCC>
    <qresource prefix="/">
        <file>config.qml</file>
        <file>root/index.qml</file>
    </qresource>

</RCC>

リソースファイルです。

webservice.png
webservice.png

webservice@2x.png
webservice@2x.png

画像ファイルですね。

git.ignore
*.pro.user*

以上が必要なファイルになります。

ファイルの置き場所は Adding New Custom Wizards の方に記載があり、

  • Qt Creator のインストールパス/share/qtcreator/templates/wizards
  • $HOME/.config/QtProject/qtcreator/templates/wizards ... Linux と macOS
  • %APPDATA%\QtProject\qtcreator\templates\wizards ... Windows

となっています。

~/.config/QtProject/qtcreator/templates/wizards/qtwebserviceapplication $ find
.
./webservice.png
./webservice@2x.png
./config.qml
./main.cpp
./app.pro
./root
./root/index.qml.tpl
./git.ignore
./wizard.json
./qml.qrc

新しいウィザードが追加されました

image.png

まとめ

今回の記事では Qt Creator のスニペット機能とウィザードの追加について紹介しました。
どちらも簡単にいじれるとても便利な機能ですので、毎回毎回同じようなことを繰り返すのが面倒になった際には是非お試しください。

明日は @taniho_0707 さんによる Qt for Androidで広告を掲載する です。お楽しみに!

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.