OSS アプリケーションとプログラミング言語についての一考察(翁長)
は じ め に
現在 PC-UNIX で用いられる主なデスクトップ環境として,オープンソー ス・ソフトウェア(OSS)のデスクトップ環境である KDE や GNOME が利用 されている。これらの OSS デスクトップ環境におけるシステムツールやアプ リケーションの開発には,それぞれ Qt と GTK というアプリケーション開発 フレームワークが使われている。GTK は C 言語,Qt は C++ 言語で記述され
1 )
1 ) 2 )2 )
3 ) 3 ) 4 )4 )
論 文
OSS アプリケーションと
プログラミング言語についての一考察
翁 長 朝 英
(京都学園大学経営学部論集 第21巻第 1 号 2011年10月 55頁〜72頁)
要約 新しい OSS アプリケーションの開発フレームワークである Qt Quick とその開発言語である QML について考察している。特に,従来の Qt で用い られていたモデル/ビューアーキテクチャが,QML においてどのように取り 扱われているか,考察した。QML は,アプリケーションのユーザーインター フェースを記述する宣言型の言語であり,言語構造が簡単で解り易い言語であ る。また,JavaScript や C++ 言語と組み合わせて,複雑な処理を行うことも 可能である。QML は,現在モバイルデバイス用のシステムアプリケーション の開発に利用されており,QML によるアプリケーションの作成技法の研究は,
今後さらに重要になることを指摘している。
キーワード:OSS,Qt,QML
1 ) KDE Community http://www.kde.org 2 ) GNOME Project http://www.gnome.org
3 ) Qt Project http://qt-project.org http://qt.nokia.com/title-jp/
4 ) GTK+ Project http://www.gtk.org
ているため,これらのモジュールを利用したアプリケーションの作成において も,C 言語や C++ 言語を使う必要がある。
C や C++ 言語によるプログラミングは,文法の習得や言語構造の理解など,
またコンパイルの操作等の煩わしさを伴っている。そして,このような問題を 解決する方策として,Ruby や Python といったオブジェクト指向のスクリプ ト言語を用いて,GTK や Qt などのモジュールを利用する方法が取られている。
一方,今日のスマートフォンやタブレットの普及のような,モバイルデバイ スの急速な進展に伴って,新たなアプリケーション開発フレームワークの開発 も行われている。モバイルデバイスのシステムにおいては,デザインやアニ メーションを重視したタッチ操作可能なアプリケーションの開発,より迅速な アプリケーションの開発が求められている。このようなアプリケーション開発 フレームワークは,従来の開発フレームワークを拡張するように,新たなモジ ュールを追加する形で開発されてきた。Qt では,新たな開発フレームワーク として,Qt Quick(Qt Quick User Interface Creation Kit)を導入している。
Qt Quick アプリケーションの作成には,同時に導入された,宣言型のプロ グラミング言語である QML(Qt Meta-Object Language)を利用する。モバイル デバイス用のアプリケーション作成技法の特徴は,アニメーションを利用した 状態遷移の方法やデータの表示方法にある。QML は,このようなアプリケー ション作成技法に対応し,より直感的で現代的なユーザーインターフェースを 作成できる言語である。
本稿では,Qt Quick フレームワークで新たに導入された QML における,
データの表示方法について考察する。特に,従来の Qt フレームワークで採用
5 )
5 ) 6 )6 )
7 ), 8 ) 7 ), 8 )
7 ), 8 ) 7 ), 8 )
5 ) Ruby http://www.ruby-lang.org/ja/
6 ) Python http://www.python.org
7 ) Qt Quick http://qt.nokia.com/products-jp/qt-quick
8 ) Qt Quick 入門 http://labs.qt.nokia.co.jp/category/qt-quick-tutorial
OSS アプリケーションとプログラミング言語についての一考察(翁長)
されているモデル/ビューアーキテクチャの観点から,QML でデータがどの ように取り扱われているか考察する。
Ⅰ Qt Quickと
QML
1 Qt Quick
Qt Quick は,Qt のバージョン4.7から導入されている。これは,QML,Qt Creator,QtDeclarative モジュールの 3 つの要素から構成されている。QML は,CSS(Cascading Style Sheets)に似た構造を持つ,宣言型のプログラミング 言語である。アプリケーションのユーザーインターフェースを簡単に記述でき る特長がある。また,アプリケーションの振舞いは JavaScript 言語を用いて 記述され,この点においても理解し易い言語になっている。
Qt Creator は,アプリケーションの統合開発環境である。これは Qt プログ ラム開発用として以前から利用されていたが,Qt Quick の導入と同時に,
QML プログラムの開発用途にも利用できるように拡張されている。
3 つ目の要素である QtDeclarative モジュールが,QML プログラムを実行 するためのランタイムを提供するモジュールである。このモジュールによって,
QML プログラムは,Qt のオブジェクトとして実行される。また,QML プロ グラムと Qt の C++ プログラムを組み合わせたアプリケーションを開発する 際に必要となるモジュールである。
2 QML
下記のリスト 1 のプログラムは,図 1 に示してあるサンプルアプリケーショ ンを QML で記述したプログラムである。
9 ) 9 )
9 ) Model/View Programming Qt4.7 Documents
http://doc.qt.nokia.com/latest/model-view-programming.html
このサンプルアプリケーションは, 1 個のラベルと 2 個のボタンで構成され ている。起動直後は「Label」と表示されるが,「Hello」ボタンをクリックす ると「Hello World!」と表示し,「Quit」ボタンをクリックすると終了するアプ リケーションである。
他の言語との比較として,付録に GTK と C 言語,Qt と C++ 言語,Qt を バインディングした Python 言語のプログラムを掲載してある。これらの言語 と比較して,QML ではアプリケーションの構造,ラベルやボタンなどの各部 品の設定や処理などが理解し易くなっていることが,一見して分かるであろう。
QML で 記 述 さ れ た プ ロ グ ラ ム を 実 行 す る 方 法 は 2 つ あ る。 1 つ は,
QDeclarativeView クラスや QDeclarativeEngine クラスを用いて C++ プログ ラム内で QML プログラムを呼び出す方法である。 2 つ目は,QML Viewer ツールを利用する方法である。後者の方法では,C++ プログラムの作成は必 要とせず,インタープリタのように利用することができる。
10)
10)
10) QtQuick 基本モジュール以外に QtDesktop モジュールも使用している。
http://qt.gitorious.org/qt-components/desktop/
図 1 サンプルアプリケーション
OSS アプリケーションとプログラミング言語についての一考察(翁長)
リスト 1 QML プログラム import QtQuick 1.0 import QtDesktop 0.1 Rectangle {
width: 200 height: 60 Column { spacing: 10
anchors.centerIn: parent Text {
id: label
anchors.horizontalCenter: parent.horizontalCenter text: "Label"
} Row { spacing:8 Button { id: button1 text:"Hello"
width: 80
onClicked: label.text = "Hello World!"
} Button { id:button2 text:"Quit"
width: 80
onClicked: Qt.quit() }
} } }
Ⅱ QMLにおけるデータの取扱い
1 モデル/ビューアーキテクチャ
Qt では,データの取り扱いにモデル/ビューアーキテクチャを採用してい る。これは,デザインパターンで言われる,モデル/ビュー/コントローラ
(MVC)アーキテクチャから,ビューとコントローラを統合したアーキテクチ
ャである。Qt では,コントローラの代わりとして,デリゲートを採用している。
Qt アプリケーションでは,モデルとビューをデフォルトの状態で利用する場 合は,モデルとビューを統合したクラスである QListWidget や QTableWidget,
QTreeWidget などを利用してデータの表示を行うこともできる。
QML におけるデータの取り扱いにも,このモデル/ビューアーキテクチャ が採用されている。しかしながら,QML では,モデルとビューを統合したク ラスはなく,これらを組み合わせてデータを表示するようになっている。
モ デ ル の 要 素(Element)に は,ListModel,XmlListModel,VisualItem- Model,VisualDataModel などがある。また,データの表示を担うビュー要素 としては,ListView,GridView,Repeater などがある。
2 モデルとビュー
通常の文字データや数値データを取り扱う場合は,ListModel を利用する。
各データアイテムの設定には,ListElement 要素が用いられる。リスト 2 に ListModel を利用したデータ設定の一例が示してある。
ListElement による各データの設定は,ロール(role)を用いて行う。 name や cost がロールである。これらのロール名はデータの設定とともに,ビ
11)
11)
11) Qt Reference Documentation http://doc.qt.nokia.com/4.7-snapshot/qml-listmodel.html
OSS アプリケーションとプログラミング言語についての一考察(翁長)
ューにデータを表示する際デリゲートによる参照に利用される。リスト 3 は,
ListView によるデータ表示の一例である。データは,リスト形式で表示される。
データをテーブル形式で表示するには,GridView 要素を用いる。リスト 3 の ListView を GridView に変更すれば,テーブル形式の表示となる。また,
セルの幅や高さは,cellWidth や cellHeight プロパティで変更できる。QML においては,GridView で使用するデータモデルはリスト形式のモデルである。
twitter アプリケーションや flickr アプリケーションのように,XML 形式の データを取り扱う場合は,XmlListModel 要素を利用する。source プロパティ で,読み込む XML 文書を指定する。ネットワーク上の XML 文書を利用する 場合は,その URL を指定する。また,query プロパティで,XML 文書内の読 み込むデータの位置を指定する。
モデルに読み込むデータは,このモデルでは XmlRole 要素を用いて設定す る。XmlRole では,name プロパティでロール名を設定し,query プロパティ リスト 2 ListModel
ListModel { id: fruitModel ListElement { name: “Apple”
cost: 2.45 }
ListElement { name: “Orange”
cost: 3.25 }
ListElement { name: “Banana”
cost: 1.95 }
}
でロール名に対応したデータを設定する。XmlListModel で定義されたモデル のデータは,ListView を用いて表示できる。flickr 画像のサムネール表示に使 用する XmlListModel と対応する XML 文書の一例をリスト 4 に示す。
色付けされた矩形のようなビジュアルデータには,VisualItemModel を利用 する。このモデルで設定されたビジュアルアイテムは,ListView や GridView を用いて表示する。VisualItemModel では,モデル内にデリゲートが組み込ま れている。そのため,ビューはデリゲートを必要としない。
VisualDataModel は QML の特徴的なモデルである。このモデルでは,モデ ル内にデリゲートをカプセル化して利用する。特に,Package 要素とともにマ ルチビューの表示を行なったり,ツリー形式のデータを取り扱う際に,データ アイテムのインデックス(index)操作に用いられる。Package 要素を用いたマ
12)
12)
12) QtQuick Examples http://jryannel.wordpress.com/2010/02/24/
using-the-listview-with-an-xml-model/
リスト 3 ListView Rectangle {
width: 200; height: 200 ListModel {
id: fruitModel ・・・・
} ListView {
anchors.fill: parent model: fruitModel delegate: Text {
text: name + “ $” + cost }
} }
OSS アプリケーションとプログラミング言語についての一考察(翁長)
ルチビューの一例をリスト 5 に示す。また,ツリー形式のデータの取り扱いに ついては,次章で考察している。
Ⅲ 考 察
前章で示したように,QML におけるデータの設定と表示には,ロール名が 大きな役割をしている。従来の Qt にも,データアイテムの属性を示すロール
13)
13)
13) Qt Reference Documentation http://doc.qt.nokia.com/4.7-snapshot/qml-package.html 例示されたプログラムを一部変更してある。
リスト 4 XmlListModel と XML 文書 XmlListModel {
id: model
namespaceDeclarations: “declare namespace media=
\”http://search.yahoo.com/mrss/\”;”
source: “http://api.flickr.com/services/feeds/
photos̲public.gne?format=rss2”
query: “/rss/channel/item”
XmlRole { name: “thumbnail”
query: ʻmedia:thumbnail/@url/string()ʼ } }
対応する XML 文書の一部
<?xml version=”1.0” encoding=”utf-8”?>
<rss>
<channel>
<item>
<media:thumbnail
url=”http://farm5.static.flickr.com/xxx.jpg” />
</item>
<item>
<media:thumbnail
url=”http://farm5.static.flickr.com/yyy.jpg” />
</item>
・・・・
がある。Qt では,モデルの既定クラスを利用する際は,ロールを使う必要は ないので,ロールは表には現れない。しかしながら,カスタムモデルを作成し て利用する場合は,ロールを用いて表示するデータの設定を行う。QML にお いてもロールの役割は Qt と同様である。Qt のロールの他に新たなロールを追 加して利用している。これは,QtSDK に付属している,QAbstractListModel を親とするカスタムモデルと ListView のサンプルプログラムから読み取るこ とができる。その一部をリスト 6 に示す。
Qt::UserRole が Qt で定義されたロールである。これには一意的に数字が割 リスト 5 VisualDataModel と Package
Delegate.qml Package {
Text { id: listDelegate; width: 200; height: 25; text: display;
Package.name: ʻlistʼ }
Text { id: gridDelegate; width: 100; height: 50; text: display;
Package.name: ʻgridʼ } }
main.qml
VisualDataModel { id: visualModel delegate: Delegate {}
model: myModel }
ListView {
width: 200; height: 200 model: visualModel.parts.list }
GridView {
x: 200; width: 200; height: 200; cellHeight: 50 model: visualModel.parts.grid
}
OSS アプリケーションとプログラミング言語についての一考察(翁長)
り当てられ,UserRole には一番大きな32が割り当てられている。QML で使用 するロールは,Qt::UserRole の値に 1 を加えて設定し,新たなロールとして作 成される。
Qt には,リストやテーブル,ツリー形式のデータモデルが用意されている。
これらのデータは,それぞれ QListView,QTableView,QTreeView を用い て表示する。しかしながら,QML で用意されているデータモデルは,リスト 形式のモデルである。データをテーブル形式で表示するには GridView を用い るが,設定するモデルはリスト形式のモデルである。
ツリー形式のデータを取り扱うには,VisualDataModel を利用する。このモ リスト 6 カスタムモデルとロール
model.h
class AnimalModel : public QAbstractListModel {
・・・・
public:
enum AnimalRoles {
TypeRole = Qt::UserRole + 1, SizeRole
};
・・・・
};
model.cpp
AnimalModel::AnimalModel(QObject *parent) : QAbstractListModel(parent)
{
QHash<int, QByteArray> roles;
roles[TypeRole] = “type”;
roles[SizeRole] = “size”;
setRoleNames(roles);
}
デルには,rootIndex プロパティと modelIndex メソッドが備わっており,ツ リー形式のモデルにおけるデータアイテムのモデルインデックス(QModel-
Index)を取得したり,取得したインデックスを親として設定することが可能
である。
ツリー形式のデータを扱う VisualDataModel の一例をリスト 7 に示してあ る。dirModel は Qt の QDirModel で定義されたモデルであり,ディレクトリ 構造をツリー形式で表すデータモデルである。ディレクトリ名をクリックする と,そのデータアイテムが子のノードをもつ場合は,アイテムのモデルインデ
14)
14)
14) Qt Reference Documentation
http://doc.qt.nokia.com/4.7-snapshot/qml-visualdatamodel.html リスト 7 ツリー形式データモデルと VisualDataModel
ListView { id: view width: 300 height: 400
model: VisualDataModel { model: dirModel delegate: Rectangle { width: 200; height: 25 Text { text: filePath } MouseArea { anchors.fill: parent onClicked: {
if ( model.hasModelChildren ) view.mode.rootIndex =
view.model.modelIndex(index) }
} } } }
OSS アプリケーションとプログラミング言語についての一考察(翁長)
ックスを取得し,ルートのデータアイテムとして設定する。そしてこのノード を起点に,ディレクトリの内容がリスト形式で表示される。
ここで使用するデータは,QAbstractItemModel やそのサブクラスで定義さ れる階層構造をもつデータである。Qt のモデル/ビューアーキテクチャで取 り入れられたデータ構造を基に,QML でも同様なデータが扱えるように拡張 されている。
お わ り に
本稿では,OSS デスクトップ環境の基礎をなすアプリケーション開発フレー ムワークの一つである Qt について考察した。特に,最近導入された新しいア プリケーション開発フレームワークである Qt Quick におけるデータの取り扱 いについて考察した。
Qt Quick で使用している QML は,本来ユーザーインターフェースを記述 するような宣言型言語であり,本稿で指摘したように,言語構造が簡単で分か り易い言語である。一般的なアプリケーションでは,複雑な処理も必要となる が,これは JavaScript や C++ 言語と組み合わせて利用することで可能である。
また,Qt Quick には,アプリケーション開発ツールとして Qt Creator 統合開 発環境が備わっている。この開発環境では,GUI(Graphical User Interface)の デザインツールを利用して,手軽にアプリケーションの開発が行えるようにな っている。
このような状況から,現在 QML は通常のアプリケーションの作成のみなら
ず,OS(オペレーティングシステム)のシステムアプリケーションの作成にも利用
されるようになっている。例えば,モバイルデバイス用途では MeeGo や KDE15)15)
15) MeeGo Project http://meego.jp http://apidocs.meego.com
本稿執筆中に、MeeGo プロジェクトは新しいプロジェクトへ移行することがアナウンスされた。
プロジェクトの PlasmaActive に利用され,デスクトップ用途では Ubuntu デ ィストリビューションの Unity2D デスクトップに利用されている。
今後,Qt Quick は多くの OSS システムにおいて,そのシステムツールやア プリケーションの開発に用いられることが期待される。その際には,本稿で考 察した QML におけるデータの取り扱い方法やアニメーションを利用した独特 なアプリケーションの開発技法などが重要になってくるであろう。
参考文献
1 .Jasmin Blanchette, Mark Summerfield 杵渕 聡,杉田研治 訳 「入門 Qt4プログラミング」 オライリー・ジャパン,2010.
2 .朝木卓見 『Qt を理解しよう』「Smartphone World」Vol.2 p.96 CQ 出版,2011.
3 .高橋和良 『Qt で MeeGo アプリを作ろう』前掲書 p.104.
4 .Qml Presenting Data, Qt Essentials ‒ Training Cource http://qt.nokia.com 5 .Qt Reference Documentation http://doc.qt.nokia.com/4.7-snapshot/
各種ドキュメント
本論文に出てくる製品名等は,各社の商標および登録商標です。
付録 他の言語を用いたプログラム リスト 1 GTK プログラム
#include <gtk/gtk.h>
static void
quit̲button̲clicked (GtkWidget *button, gpointer user̲data) {
gtk̲main̲quit ();
}
16)
16)
17)
17)
16) Plasma Active Project http://plasma-active.org http://community.kde.org/Plasma/Active/Development 17) Unity2D Project https://wiki.ubuntu.com/Unity2D
OSS アプリケーションとプログラミング言語についての一考察(翁長)
hello̲button̲clicked (GtkWidget *button, gpointer user̲data) {
gtk̲label̲set̲text (GTK̲LABEL (user̲data), "Hello World!");
}
int
main (int argc, char **argv) {
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *button1;
GtkWidget *button2;
gtk̲init (&argc, &argv);
window = gtk̲window̲new (GTK̲WINDOW̲TOPLEVEL);
gtk̲window̲set̲title (GTK̲WINDOW (window), "Hello");
gtk̲widget̲set̲size̲request (window, 200, 100);
gtk̲container̲set̲border̲width (GTK̲CONTAINER (window), 10);
g̲signal̲connect (G̲OBJECT (window), "destroy", G̲CALLBACK (gtk̲main̲quit), NULL);
vbox = gtk̲vbox̲new (TRUE, 5);
gtk̲container̲add (GTK̲CONTAINER (window), vbox);
label = gtk̲label̲new ("Label");
gtk̲box̲pack̲start (GTK̲BOX (vbox), label, TRUE, TRUE, 0);
hbox = gtk̲hbox̲new (FALSE, 0);
gtk̲box̲pack̲start (GTK̲BOX (vbox), hbox, TRUE, TRUE, 0);
button1 = gtk̲button̲new̲with̲label ("Hello");
gtk̲box̲pack̲start (GTK̲BOX (hbox), button1, TRUE, TRUE, 0);
button2 = gtk̲button̲new̲with̲label ("Quit");
gtk̲box̲pack̲start (GTK̲BOX (hbox), button2, TRUE, TRUE, 0);
g̲signal̲connect (G̲OBJECT (button1), "clicked",
G̲CALLBACK (hello̲button̲clicked), (gpointer) label);
g̲signal̲connect (G̲OBJECT (button2), "clicked", G̲CALLBACK (quit̲button̲clicked), NULL);
gtk̲widget̲show̲all (window);
gtk̲main ();
return 0;
}
リスト 2 QT プログラム main.cpp
#include <QtGui/QApplication>
#include "hello.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Hello *w = new Hello;
w->show();
return a.exec();
} hello.h
#ifndef HELLO̲H
#define HELLO̲H
#include <QWidget>
class QLabel;
class Hello : public QWidget {
Q̲OBJECT
OSS アプリケーションとプログラミング言語についての一考察(翁長)
public:
Hello(QWidget *parent = 0);
public slots:
void setLabelText();
private:
QLabel *label;
};
#endif // HELLO̲H hello.cpp
#include "hello.h"
#include <QtGui>
Hello::Hello(QWidget *parent) : QWidget(parent) {
label = new QLabel("Label");
label->setAlignment(Qt::AlignHCenter);
QPushButton *button1 = new QPushButton("Hello");
QPushButton *button2 = new QPushButton("Quit");
connect(button1, SIGNAL(clicked() ), this, SLOT(setLabelText() ) );
connect(button2, SIGNAL(clicked() ), this, SLOT(close() ) );
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(button1);
hbox->addWidget(button2);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(label);
vbox->addLayout(hbox);
setLayout(vbox);
}
void Hello::setLabelText() {
label->setText("Hello World!");
}
リスト 3 Python プログラム(PyQt)
from PyQt4.QtCore import * from PyQt4.QtGui import * class Hello(QWidget):
def ̲̲init̲̲(self, parent=None):
super(Hello, self).̲̲init̲̲(parent) self.label = QLabel("Label", self) self.label.setAlignment(Qt.AlignHCenter) self.button1 = QPushButton("Hello", self) self.button2 = QPushButton("Quit", self) vbox = QVBoxLayout()
hbox = QHBoxLayout() vbox.addWidget(self.label) hbox.addWidget(self.button1) hbox.addWidget(self.button2) vbox.addLayout(hbox) self.setLayout(vbox)
self.button1.clicked.connect(self.on̲hello̲button̲clicked) self.button2.clicked.connect(qApp.quit)
def on̲hello̲button̲clicked(self):
self.label.setText("Hello World!") if ̲̲name̲̲ == '̲̲main̲̲':
import sys
app = QApplication(sys.argv) win = Hello()
win.show()
sys.exit( app.exec̲() )