読者です 読者をやめる 読者になる 読者になる
おもに Groovy やアジャイル開発について勉強していることを書き散らしてます。
わたしのひとりごとが、だれかのお役に立てればと…

QQmlApplicationEngine と QtQuick2ApplicationViewer(QQuickView) の違い

Qt

Qt を少しずつ勉強していってます。 Qt(主に Qt 4)は書籍があるので勉強しやすかったけれど、 Qt Quick(QML)は書籍もなく、がっつりまとまったサイトもないため、苦戦中。

とりあえず今日ハマってしまったところをまとめてみる。

似たような、ふたつのクラス

QML の入門的なサイトを見てみると、main 関数のあるソース(main.cpp)のなかで、QtQuick2ApplicationViewer なるクラスを使っているサイトをちらほら見かける。

ところが、私が使っている Qt Creator(バージョン 4.0.3)では、 「Qt Quick アプリケーション」を選択して新規プロジェクトを作ってみても、 QtQuick2ApplicationViewer は使用されない。 代わりに QQmlApplicationEngine クラスが使用される。

同じようなロジックのようなのだが、相違はどうなんだろうと調べてみた。
(こんなことを調べずに早く先に進みたかったのだが)

QtQuick2ApplicationViewer とは

うまく言及してくれているサイトがあった。

tips.hecomi.com

以下、ちょうどいい箇所を抜粋。

QtQuick2ApplicationViewer は Qt Creator で Qt Quick 2 プロジェクトを生成すると生成され、プラットフォーム間の違いを吸収してくれる処理が書いてある QQuickView 派生クラス(元を辿ると QWindow 派生クラス)です

API のクラス一覧にも存在しないので、なんだろうと思っていたら…そういうことかと。

その元となる QQuickView は Qt 5.0 から実装されたクラス。
http://doc.qt.io/qt-5/qquickview.html

QtQuick2ApplicationViewer とは

QQmlApplicationEngine は Qt 5.1 から実装されたクラス。
http://doc.qt.io/qt-5/qqmlapplicationengine.html

これらのクラスの違いは?

QQuickView の API ドキュメントを見ると…

The QQuickView class provides a window for displaying a Qt Quick user interface.

一方で、QtQuick2ApplicationViewer の API ドキュメントは…

Unlike QQuickView, QQmlApplicationEngine does not automatically create a root window. If you are using visual items from Qt Quick, you will need to place them inside of a Window.

QtQuick2ApplicationViewer の方には、QQuickView と対比した説明がある。 アプリケーションを表示するにあたって、ウィンドウが自動的に作られるか、そうでないかで違うとのこと。

QQuickView は自動的にウィンドウが作られる、むしろ自分自身がウィンドウなので、QML で "Window" を配置する必要がない。 一方で、QQmlApplicationEngine は自動的に作られないので、QML で "Window" を配置してあげる必要がある。

実際にソースコードを書いてみた

まず、QML を2つ用意する。

① Window なしの QML(nowrapWindow.qml)

import QtQuick 2.7

Rectangle {
    width: 640
    height: 480

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}

外側に Window を配置せず、矩形(Rectangle)だけ。 QQuickView で使う想定。

② Window ありの QML(wrapWindow.qml)

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}

Window を外側に配置しておく。QQmlApplicationEngine で使う想定。

起動元となる C++ ソースコード(QQuickView)

#include <QGuiApplication>
#include <QtQuick/QQuickView>

int main(int argc, char **argv) {
    QGuiApplication app(argc, argv);

    QQuickView *view = new QQuickView;
    view->setSource(QUrl(QStringLiteral("qrc:/nowrapWindow.qml")));
    view->show();

    return app.exec();
}

「Window なしの QML」を読み込んでも、きちんとウィンドウが現れて内容が表示される。

逆に「Window ありの QML」を読み込むと、ウィンドウがふたつ現れてしまう。
ひとつは空っぽのウィンドウ(QQuickView に対応?)で、もうひとつは中身が表示されたウィンドウ(QML 内の Window に対応?)。

起動元となる C++ ソースコード(QQmlApplicationEngine)

#include <QGuiApplication>
#include <QQmlApplicationEngine>

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

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

    return app.exec();
}

QQmlApplicationEngine はウィンドウを自動的に作らないので、 「Window ありの QML」を読み込むことで、ウィンドウが現れて QQuickView と同様の表示を行うことができる。

一方で、「Window なしの QML」を読み込んだ場合、ウィンドウが作られずに何も表示されない状態になってしまう(アプリケーション自体は動いているが)。

まとめ

「(正規の API ではない)QtQuick2ApplicationViewer ってなんだ?」でハマり、時間を食ってしまったので、まとめてみた。
まとめてみたけど、わかってしまえば大したことない話…

この二つのクラス、さらに使い分けがありそうな雰囲気がするけれど、とりあえず今のところは無視しよう。

Qt と QML はやっぱり情報源が少ないのがつらいね、初心者には。

また TOEIC だ

TOEIC

また今年も TOEIC をやることになった。

会社のお金で TOEIC を年1回くらい受けさせてもらったり、
自腹で何度か受けにいったこともある。

リスニングの点数がなかなか上がらない。
というか、リスニングはほぼ上がっていなくて、
リーディングだけがぐんぐん上がっていく。

けれど、リーディングだけでは限界で、
一定レベル以上のスコアはだせない(ビジネスパーソン平均よりもちょっといい程度)。

リスニングはたぶん壁にぶちあたっていて、
壁を乗り越えないといけない時期なんだろうなという感じ。

とはいえ、英語を勉強することだけに集中することもできずに
いつまでたっても壁の前をウロウロしている。

永遠の優先順位 第3位

・・・と、自分が英語に取り組む姿勢を捉えている。

優先順位の第1位、第2位はマイブームだったりで、コロコロ変わる。
当然そのあたりにある業務、作業、そして趣味には時間を費やす。
一方で、ある時期は第1位だったものが、いきなり圏外に転落するという側面もある。

でも、英語だけは第3位という中途半端な位置をキープし続け、
いつもかすかに意識させられる存在。手を動かすことはないのに。

どうしたらいいんだろうね、今年は。

Gradle の社内勉強会をしてきた

Gradle

・・・と言うものの、実際に勉強会をしたのは
半年前の 2015年11月 なんですが。

せっかく説明資料もサンプルコードもたくさん作ったので
どこかにアップでもしようかと思いながら、ようやくアップした次第です。

https://speakerdeck.com/hideoku/ming-ri-karashi-itakunaru-gradle

サンプルコードは GitHub にアップしてます。
https://github.com/hideoku/GradleLabo

勉強会をやった経緯

うちの部署では、ハンズオン形式で技術勉強会をやってました。
ひとり1回は講師をしないといけないということで、私は Gradle の入門を。

Gradle 大好きなので、みんなにもとにかく使ってもらおうかなと。

Gradle を使ってみようと思ってもらうことが重要なので
ちょっと偏ってますが「Gradle = 便利ツール」というスキームでやりました。

ビルドツールとして紹介すると、弊社の実情的にまだまだ先進的で、
自分には関係ないやと思われると終わり。それはダメだなと。

準備をとにかくがんばった

どうせ勉強会で紹介したって、後に続かない。
自分で手を動かしてなにか挑戦してみるところまで、なかなかつながらない。

そういうあきらめというか、限界は感じてました。

どうしたら手を動かしてもらえるのかを考えたときに・・・

  • 勉強会の資料だけで、ひとり歩きするくらいのボリュームにしよう
  • はじめの一歩でつまづくときに手助けになるサンプルをたくさん作ろう

この2点を抑えておけば、後から挑戦してみようと思いたったときや
必要にかられて Gradle を勉強せざるを得なくなったときに
説明資料やサンプルコードが助けになるはずだと考えて、準備がんばりました。

勉強会の反響

10数人くらい参加してくれました。
目の前には2人しかいなくて、残りはリモート参加という異様な形でしたが。

「やってみたくなった」というコメントが多かったので、
やってよかったなと素直に思いました。

準備に結構な時間をついやしたので、報われました。

とはいえ、半年たった今、Gradle が浸透しているかというと
そんなことはなさそうです。 必要にかられないと、なかなか実際に使おうとは思わないのが実情です。

おわりに

はじめて Speaker Deck にアップしてみた。

組み込み技術者になりました

ひさかたぶりのブログです。
この2ヶ月で、大きく環境が変化したのでそのことについて書き連ねてみます。

この4月に部署異動となり、Web アプリ開発者から組み込み技術者になりました。

バタバタしている間に本日、6月に突入し、もう2ヶ月か…なんかやばい。
…と思い、ブログを書いてみんとす。

車載ソフトウェア開発

いわゆる、「車載ソフトウェア開発」をすることになりました。
カーエレクトロニクスという分野ですね。

組み込みも分からない、クルマも分からない、C言語も知らない。
そういう最悪の状況です。

Webアプリ から 組み込み へ

10数年ほど、ずっと Java で Web アプリ開発をしてきたわけです。
それがいきなりの畑違いの組み込みに異動です。
ソフトウェア開発といえば同じですが、やっていることは全く異なります。

業務知識、ITスキルともに素人レベルまで落ち込みました。

ハードウェアやネットワーク、そういった物理に近いところでの会話が圧倒的に多くなりました。

Web アプリやら、Java やらやっていると、そういうのは全く意識しないので
いまさらながらに基本的なところから勉強しなおしています。

組み込み開発ではリソースの制約がきびしく、メモリがたった数百KBだったりします。
(ヒープ圧迫してるから、メモリ割り当て 2GB に変更…なんて、異なる世界)

Write once, run anywhere

リソースの制約もそうですが、ハードウェア(マイコン)ごとにコンパイラが違うというのが驚きでした。 コンパイラだけでなく、ソースコードもハードウェア構成によって調整が必要です。

ハードウェアを意識して、プログラミングする必要があります。
リソースも当然気にしないといけない。
これは大変だと。

Java では「Write once, run anywhere」というキーフレーズを目にしてたのですが、
JVM の上で動くから環境非依存でプログラムを使いまわせるよ…と軽く考えていました。

実際にマイコン制御やC言語のことをきちんと学んでみると、run anywhere のスゴさが実感できました。
物理とかハードウェアとかを関心事から除外して、プログラミングできるのはすばらしい。

多くの Java 技術者は「Write once, run anywhere」を理解していないだろうな。

ソフトウェアをインストールするときに gcc や make するのもこの辺が絡んでいるのかなと
素人的に思っています(ちゃんと調べてない)。

自分が組み込みをやる意義

Webアプリでアーキテクチャ構築とかを長年やってきたノウハウを一応持っているつもりです。

Webアプリ開発では当然のことが、組み込み開発ではやっていなかったりします。
たとえば、コンポーネント設計、フレームワーク活用、そういったものが組み込みにはなじみがないようです。
共通化や再利用がまだまだ進んでいないようです。

自分が持っていて、組み込み技術者が持っていないもの。

それがなんであるかを早く把握して、そのギャップを活かすこと。
自分しか持っていない価値を組み込み開発にフィードバックすることが求められているのだと思います。

まだまだ「郷に入っては、郷に従え」で業務知識や組み込み技術をインプットするだけで精一杯。

とはいえ、もう2か月経ったんですよね。
そろそろアウトプットしていかないと…と思い、ブログ書いてみたというわけです。

GradleでExcelを読み込んでなにかを作る

Gradle

Gradle の社内勉強会をやることになったので、ネタ集めをしています。

「Gradle、実はこういうこともできるよ」ネタを考えてたら
私がよくやるのを紹介したらいいかもと思いつきました。

Gradle はスクリプトベースのビルドツールなので、
極端な話、ガリガリとスクリプトを書けば何でもできます。

ちょっとした Excel 読み込みからの→ファイル生成を個人的によくやります。
自分用の作業テンプレートを作っておく意味もあって、まとめておきたいと思います。

Gradleタスクを作る

build.gradle は以下のような感じです。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.apache.poi:poi:3.13'
        classpath 'org.apache.poi:poi-ooxml:3.13'
    }
}

import org.apache.poi.ss.usermodel.*

task generateMessageIdJava << {

    Workbook workbook = WorkbookFactory.create(
                                  new File("メッセージマスタ.xls"))
    Sheet sheet = workbook.getSheetAt(0)

    new File("MessageId.java").withWriter("UTF-8") { writer ->

        writer << "package sample.constants;\n\n"
        writer << "public class MessageId {\n\n"

        (3 .. sheet.getLastRowNum()).each { rownum ->
            Row row = sheet.getRow(rownum)

            String messageId = row.getCell(0).getStringCellValue()

            // メッセージIDが記載されていない行は書き出さない
            if (messageId?.length() == 0) return

            String message = row.getCell(1).getStringCellValue()

            writer << "    /** $message */\n"
            writer << "    public static final String $messageId"
            writer <<                             " = \"$messageId\";\n"
            writer << "\n"
        }

        writer << "}"
    }
}

やっていること
・buildscript ブロックで Apache POI を使えるように依存関係を設定します。
・同様に、Apache POI が使えるように import 文を追加します。
Excel を1行ずつ読み込みながら、出力ファイルに1行ずつ書き出します。

build.gradle と読み込む Excel ファイルは同じフォルダにある想定です。
出力ファイルも同じフォルダに生成します。

Excel ファイルの中身はこんな感じです。
よくあるマスタ定義ファイルです。

f:id:hideoku:20151111010422p:plain

build.gradle と同じディレクトリに Excel ファイルを配置しておきます。

[とあるフォルダ]
├build.gradle
├メッセージマスタ.xls
└(MessageId.java

タスクを実行してファイルを生成する

gradle generateMessageIdJava

タスクを実行すると、以下のようなファイルが出力されます。
よくみる定数定義ファイルです*1

package sample.constants;

public class MessageId {

    /** 検索しました。検索結果は{0}件です。 */
    public static final String MSG001 = "MSG001";

    /** 登録しました。 */
    public static final String MSG002 = "MSG002";

    /** ユーザIDとパスワードを入力してログインしてください。 */
    public static final String MSG003 = "MSG003";

    /** {0}は入力必須です。 */
    public static final String MSG004 = "MSG004";

    /** {0}は{1}以下の数値で入力してください。 */
    public static final String MSG005 = "MSG005";

}

応用例

このような Gradle タスクを Jenkins などの CI に組み込めば、
設計書が SCM(Subversion, Git etc)にコミットされたのを検知して
自動的に設計書に対応したソースコードを生成して、コミットする
…なんてこともできます。
面倒なルーチンタスクからの解放です。

Gradle Wrapper を使えば、Gradle インストールしていない人にも
使ってもらうことができますね。

*1:こういう定数定義ファイルに意味があるのかどうかは横に置いておきます。そういうものが必要とされる職場があるのだということで。