わたしのひとりごとが、だれかのお役に立てればと…

Angular で JointJS を動かすための最初の一歩

Angular に JointJS(https://www.jointjs.com/opensource)を組み込んでグラフ描画を実装しているのですが、日本語の情報がなくて苦労しました。
メモっておいたら役立つかもということで、まずは導入部分での工夫を今回まとめます。

使用しているバージョンはこちら。

パッケージ バージョン
@angular/core 5.2.9
@angular/cli 1.7.4
jointjs 2.0.1

公式サイトのチュートリアルに沿って、動かせる所までやってみます。
https://resources.jointjs.com/tutorial/hello-world

JointJS のパッケージをインストールする

npm install --save jointjs

ここは悩みどころはないはずです。

JointJS を使えるように Component に import する

import { Component, OnInit } from '@angular/core';

import * as joint from 'jointjs';

@Component({
  selector: 'app-simple',
  template: '<div id="myholder"></div>',
  styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnInit {
  graph = new joint.dia.Graph;

  constructor() { }

  ngOnInit() {
  }
}

まずは上記のように import * as joint from 'jointjs'; としたいところですが、

node_modules/jointjs/dist/joint.d.ts(1395,34): error TS2503: Cannot find namespace 'JQuery'.

という具合にコンパイルエラーが発生します。

そこで、「import * as joint from 'jointjs';」の代わりに以下のようにして 'jointjs' を使えるようにしました。

declare function require(x: string): any;
const joint = require('jointjs/dist/joint.js');

TypeScript のコンパイラが以下のような require が見つからないとエラーを発生させるので
2行目のように require 関数を宣言してあげる必要があります。

const joint = require('jointjs/dist/joint.js'); ERROR in src/app/simple/simple.component.ts(6,15): error TS2304: Cannot find name 'require'.

Hello World サンプルコード全体

ということで、チュートリアルを動かすサンプルコード全体。
所々で TypeScript 向けに変更してます。

import { Component, OnInit } from '@angular/core';

declare function require(x: string): any;
const joint = require('jointjs/dist/joint.js');

import * as $ from 'jquery';  /* joint.dia.Paper の初期化で $ を使うため */

@Component({
  selector: 'app-simple',
  template: '<div id="myholder"></div>',
  styleUrls: ['./simple.component.css']
})
export class SimpleComponent implements OnInit {

  graph = new joint.dia.Graph;

  paper;

  constructor() { }

  ngOnInit() {
    this.paper = new joint.dia.Paper({
      el: $('#myholder'),
      width: 600,
      heigth: 200,
      model: this.graph,
      gridSize: 1
    });

    const rect = new joint.shapes.basic.Rect({
      position: { x: 100, y: 30 },
      size: { width: 100, height: 30 },
      attrs: { rect: { fill: 'blue' }, text: { text: 'my box', fill: 'white' } }
    });

    const rect2 = rect.clone();
    rect2.translate(300);

    const link = new joint.dia.Link({
      source: { id: rect.id },
      target: { id: rect2.id }
    });

    this.graph.addCells([rect, rect2, link]);
  }
}

参考サイト

ここがなかったら無理でした。 github.com

QQmlApplicationEngine と QtQuick2ApplicationViewer(QQuickView) の違い

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 を年1回くらい受けさせてもらったり、
自腹で何度か受けにいったこともある。

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

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

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

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

永遠の優先順位 第3位

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

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

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

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

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か月経ったんですよね。
そろそろアウトプットしていかないと…と思い、ブログ書いてみたというわけです。