概要
- Necessitas は Qt(Widget/QML)プログラムを Android 端末上で簡単に動作させるための環境
http://necessitas.kde.org/
- Qt とはマルチプラットフォーム(Win/OSX/Linux/各種組込PC/etc...)対応の C++ GUIフレームワーク
- Qt Project
- TrollTech → Nokia → Digia
- 商用版/GPL版/LGPL版があり、LGPL版を上記サイト>Download よりダウンロード可能
- フレームワークそのもの、QtCreator(IDE)、VS用アドインなどが配布されている
- デスクトップ向けの QWidget アプリと、携帯端末向け QML アプリが作成可能
- Moc により C++ 構文を拡張し、Signal/Slot による動的バインディングを実現
- GUI全般(イベント処理、動的レイアウト、フォーム、各種GUI部品、2DCG)、動的翻訳機能、ネットワーク機能など
- webkit, OpenGL, SVG, XML、マルチメディア など多くのモジュールを含む
- QML は携帯端末向けで、パーティクルや画面遷移機能などがある
- C++ だけでなく Java, Ruby, Python などから利用することも可能
- とても素直な設計で、生産性が高い
- GoogleEarth, Skype, VLC などが採用
- Ubuntu phone/tablet が標準GUI開発環境として採用。Qt/QML で開発
- 入門書:Qt プログラミング入門
- Qt は、諸般の事情で、公式には Android/iOS 未対応だったが、外部コミュニティにより、Android 版が開発された。
現在は正式ブロジェクトとして開発が進んでいる(はず)
- ライブラリは(通常)約10MBあるが、Ministro II がライブラリ共有化を実現
- 長所
- 開発環境:Win/Mac/Linux
- Win/Mac/Linux で動作するコードをほぼそのまま流用することが出来る
- C++ なので、処理そのものは Java の約10倍~100倍高速
- Ministro II により、QtライブラリのDLが1回きりでよい
- (現状の)問題点
- 2013/03 時点で、未だ正式版ではない(beta-1)
- マルチメディア(サウンド)機能、動的翻訳システム、署名機能などが未実装・不完全
- 機能によっては、JNIを使い Java をコールしなくてはいけない場合がある
- QtCreator/VS-Adin でのサポートは限定的
- ウィジェットが携帯端末に最適化されていない
- デフォルトのままではウィジェットデザインが残念すぎるし、使いづらい場合がある
- デスクトップでは画面が狭いことは稀だが、携帯端末では画面が狭く、要求される仕様が異なる
- ウィジェットが画面からはみ出す場合がある
- AndroidManifest.xml でインタネットアクセス、外部ストレージアクセスを消しても、パーミッションが消えない
- Ministro II による複数回DL(アプリ、Ministro, ライブラリと3回)にユーザが戸惑う
- iOS 対応版がいつリリースされるのかよくわからない
- Qt 自体が 5.0 に移行したばかりであり、現状では完成度がいまいち
- (日本語)情報源が少ない
- Qt ソースコード資産がある and/or C++ でプログラミングしたい人にはお薦め
※ QML で開発することも可能なようだが、筆者は未だトライしていない
セットアップ
- Download
- DLして、インストーラを起動し、あとはボタンを押すだけ(だったような気がする)。
- 筆者は Win7/OSX にセットアップしてみた。Win7版は動作させることが出来なかった
開発デモ
HelloWorld 表示してみる
- 画面に「Hello, World.」と表示させる方法はいくつかある
- デザイナを用い、ラベルテキストを「Hello, World.」とする
- ラベルウィジェットを手動で生成し、テキストを手動で設定する
- テキストが表示出来る他のウィジェットでも可
- paintEvent() を再実装し、drawText() 等を用いて「Hello, World.」を描画する
- MainWindow を直接オーバライドしてもよいし、ウィジェットを貼り付け、それをオーバライドしてもよい
- もっとも簡単なのは、デザイナを用いて、ラベルを配置する方法である
- 新規プロジェクトを作成
- ファイル一覧から ui ファイルをダブルクリックし、デザイナを開く
- フォームにラベルを配置し、テキストを「Hello, Wold.」に修正
- ビルド・実行
- このへんの使い勝手は、VS, Eclipse などの通常のIDEと大差ない
- ui ファイルはuiオブジェクトを指定するXMLファイルである
- ウィジェットのメンバ変数として Ui::MainWindowClass ui; が宣言され
- コンストラクタにて、ui.setupUi(this); により ui オブジェクトが動的に構築される
- ui をオブジェクトそのものではなく、ポインタにすることも出来る
- デザイナで配置したオブジェクトは、C++ プログラムから ui->オブジェクト 名で参照することが出来る
- デザイナを使用せず、手でラベルオブジェクトを生成することも可能
- ウィジェットの描画ハンドラ(paintEvent(QPaintEvent *))を再実装して、表示することも可能
ウィジェットをシグナルスロットでつないでみる
- Qt の最大の特徴であるシグナル/スロットの使用例
- シグナル/スロット はクラス・メソッドを動的にバインディングする仕組み
- 型安全
- Moc(Meta Object Compiler)により C++ 構文を拡張している
- connect(オブジェクト, SIGNAL(シグナル名(引数)), オブジェクト, SLOT(スロット名(引数)))) により、 シグナル/スロットを結合
- disconnect() で結合を解除することも可能
- デザイナでシグナル/スロット結合を設定可能
- フォームに スライダー(QSlider)と ダイアル(QDial)を配置
- F4 を押し、シグナル/スロット 編集モードにし、スライダーとダイアルを結合(connect)
- スライダーの valueChanged(int) シグナルと、ダイアルの setValue(int) を結合する
- ビルド・実行し、スライダーを移動すると、ダイアルが同期する
- 同様に、ダイアルの valueChanged(int) シグナルと、スライダーの setValue(int) を結合すると、完全に同期する
シグナル/スロットを実装してみる
- QObject 派生クラスは、シグナル/スロットを実装することが出来る
- シグナルは、宣言ファイルで signals: に続けて、シグナルを宣言するだけでよい。
class Hoge
{
....
signals:
void mySugnal();
};
スロットは、宣言ファイルで {public | protected | private} slots: に続けて、スロットメソッドを宣言し
class Hoge
{
....
public slots:
void mySlot();
};
実装ファイルで通常のメソッドと同様に実装する
void Hoge::mySlot()
{
....
}
タップ(クリック)イベントを処理してみる
- タッチ操作を行うと QEvent::Gesture イベントが発生する
- bool event(QEvent *event) ハンドラで処理を行うことが出来る
bool MyWidget::event(QEvent *event)
{
if (event->type() == QEvent::Gesture)
return gestureEvent(static_cast(event));
return QWidget::event(event);
}
特にイベント処理を行わない場合、マウスイベントに変換され、マウスイベントハンドラがコールされる
void QWidget::mousePressEvent ( QMouseEvent * event )
{
}
void QWidget::mouseReleaseEvent ( QMouseEvent * event )
{
}
void QWidget::mouseMoveEvent ( QMouseEvent * event )
{
}
QMouseEvent::pos() でマウス座標取得などが可能
ボタン種別は Qt::MouseButtons QMouseEvent::buttons() で取得
画像を表示してみる
- まずは画像をリソースとして登録する
- QtCreator の場合は ファイル>ファイル/プロジェクトの新規作成 を実行し、
Qt>Qt リソースファイル を選び、リソースを新規作成する
- プロジェクトディレクトリに Resource ディレクトリを作成し、画像ファイルを格納する
- mainwindow.qrc をダブルクリックし、Qt リソースエディタを起動
- Add>Add Prefix を実行し、Prefix を作成
- Add>Add Files を実行し、画像ファイルをリソースとして登録する
- リソース登録したファイルは、プログラムからは ":/prefix/リソース名" で参照することが出来る
- 画像ファイルは QPixmap に読み込み、QPainter::drawPixmap(const QPointF & point, const QPixmap & pixmap) 等で画面に表示できる
- 描画処理は paintEvent(QPaintEvent *) を再実装により行う
簡単なアニメーションをやってみる
- 2Dグラフィックスフレームワークにはアニメーション機能があるが、QWidget には無い
- QWidget派生クラスでアニメーションを行う場合は、タイマー割り込みを使用する
class MyWidget : public QWidget
{
.....
protected
void paintEvent(QPaintEvent *); // 描画ハンドラ
protected slots:
void onTimer(); // タイマー処理ハンドラ
private:
QTimer m_timer; // タイマーオブジェクト
QPointF m_pos; // 表示位置情報
}
MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
....
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
m_timer.start(1000/FPS);
}
void MyWidget::onTimer()
{
画像位置を更新;
update();
}
void MyWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QPixmap pixmap;
if( pixmap.load(":/MainWindow/Resourece/hoge.png") )
painter.drawPixmap(m_pos, pixmap);
}
動的翻訳してみる
- 新規プロジェクトを作成し、フォームに Hello, World ラベル、Translate チェックボックスを配置
- 処理スロットを追加し、チェックボックスの clicked(bool) とコネクト
- 翻訳ファイルを生成。ファイル名は testhello_ja.ts とした。
- 翻訳ファイルをダブルクリックし、Linguist を開き、Hello, World を翻訳し、保存
- 翻訳ファイルに対して lrelease を実行し、qm ファイルを生成
- 生成された qm ファイルを Resources 下に移動
- qrc ファイルを開き、生成した qm ファイルをリソースとして追加
- MainWindow に onTranslate(bool) スロットを追加する
QTranslator オブジェクトを生成し、先にリソースに追加した翻訳ファイルをロードし、
アプリケーションにインストールし、UI を再翻訳する。
class MainWindow
{
.....
protected slots:
void onTranslate(bool);
};
void MainWindow::onTranslate(bool b)
{
QTranslator translator;
if( b && !translator.load(":/MainWindow/Resources/testhello_ja.qm") )
return;
qApp->installTranslator(&translator);
ui.retranslateUi(this);
}
Translate をチェックすると、翻訳が動的に切り替わる
※ 本来であれば、ロケールを判定し、起動時に翻訳ファイルを切り替えるのが定石なのだが、
現状はロケール判定機能が未実装のようだ(JNI 経由で判定することは可能)。
端末の表示方向を固定する
出来たバイナリをアンドロイド環境で動作させる
- ターゲットを Android にし、実行アイコンクリック(または Deploy メニュー)
- 基本的にソースは共通
- 筆者は MainWindow.h, .cpp だけは別にしている
- OSにより処理を切り分けたい場合は #ifdef Q_OS_ANDROID 等を使う
- 128, 72, 48, 36px アイコン画像、1280x800 スプラッシュスクリーンも用意し、
Android/res 以下に置く
- 実機が繋がっていない場合はエミュレータが起動される
- 実機が繋がっていれば、実機で実行される
- この場合でも、一度は Ministro II をインストールする必要がある
- 筆者の環境では 4.2.2 にアップデートしたら、実機が認識されなくなってしまった orz(サポート外?)
- プロジェクト/Android/bin/プロジェクト名-Debug.apk が出来る
apk を配布