2012年12月10日

Qt+JS: QTreeWidget (3)

前回のエントリーで、ドラッグ・アンド・ドロップを実装しましたが、その代償としてGUIツールでQTreeWidgetを置いてはいけない、というものでした。基本的なコードでの設定+アルファを紹介します。

// 作成・設置
this.fileTable = new QTreeWidget();
this.widget.layout().insertWidget(0, this.fileTable);
var policy = QSizePolicy.Policy(QSizePolicy.Preferred), QSizePolicy.Policy(QSizePolicy.Preferred);
this.fileTable.setSizePolicy(policy);
// 設定いろいろ
this.fileTable.headerHidden = false;
this.fileTable.rootIsDecorated = true;
this.fileTable.itemsExpandable = true;
this.fileTable.expandsOnDoubleClick = true;
// 選択モードはExtended一択
// OS提供のものとほぼ一緒。Ctrl+Click/Shift+Clickも可になる
this.fileTable.selectionMode = QAbstractItemView.SelectionMode(QAbstractItemView.ExtendedSelection);
// コンテキストメニュー&コールバック
this.fileTable.contextMenuPolicy = Qt.CustomContextMenu;
this.fileTable.customContextMenuRequested.connect(this, this.onFileContextMenuRequested);
// キーボードのフック
this.fileTable.keyPressEvent = this.fileTableKeyTriggered.bind(this);
// その他のコールバック
this.fileTable.itemSelectionChanged.connect(this, this.onFileItemSelected);
this.fileTable.itemDoubleClicked.connect(this, this.onFileItemRenameTriggered);

selectionModeをExtendedSelectionにすると、複数の要素が同時選択できるようになります。currentItemプロパティで選択されたQTreeWidgetItemを取得することも可能ですが、最後に選択されたものしか取得できないため、コード内のcurrentItemを参照している処理はすべてselectedItems()メソッド呼び出しに変える必要があります。

キーボードのフックは次のような感じで書けます。シグナルではなくてオーバーライドなので、これも自分でnewしないと使えない機能な気がします。acceptしないと、親の方にキーイベントが中継されていってしまいます。シンプルに書いてますが、実際にはselectedItems()を取得して、選択状態に応じたifとかを入れる必要があるでしょう。

MyDialog.prototype.fileTableKeyTriggered = function (event)
{
    if (event.matches(QKeySequence.Delete) || event.matches(QKeySequence.Back))
    {
        // 処理するコードをここに書く
        event.accept();
    }
};

コンテキストメニュー表示は以下のように書きます。事前にメニューオブジェクトを作っておけば、コールバックの中は座標取得して表示して終了となりますが、大抵の場合はツリー内で選択されたアイテム数や選択された項目の種類に応じてメニュー項目を増減する必要があると思うので、コールバック内で作ることになると思います。

MyDialog.prototype.onFileContextMenuRequested = function (relativePoint)
 {
    // 何も選択されていない時は何もしない
    if (this.fileTable.selectedItems().length === 0)
    {
        return;
    }
    // 表示位置取得
    var globalPoint = this.assetKeyTable.mapToGlobal(relativePoint);

    var contextMenu = new QMenu('File Menu');
    // メニューに項目を追加
    var renameAction = contextMenu.addAction(new QIcon(), qsTr("Rename"));
    renameAction.triggered.connect(this, this.onRenameTriggered);
    // セパレータ
    assetContextMenu.addSeparator();
    // 階層構造も定義できる
    var sendMenu = new QMenu(qsTr('Send To'));

    var sendFileAction = contextMenu.addAction(new QIcon(), qsTr("File"));
    sendFileAction.triggered.connect(this.onSendTriggered.bind(this, "file"));
    var sendMailAction = contextMenu.addAction(new QIcon(), qsTr("Mail"));
    sendMailAction.triggered.connect(this.onSendTriggered.bind(this, "mail"));

    contextMenu.addMenu(sendMenu);
    // 表示
    assetContextMenu.exec(globalPoint);
};

ドラッグ・アンド・ドロップ以外の細かい設定は以上のような感じです。これらを設定するだけで、ユーザの細かい操作に対応できるツリーが作成できます。

posted by @shibukawa at 08:56 | Comment(405) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QTreeWidget (3)

2012年12月09日

Qt+JS: QTreeWidget (2)

ファイルの一覧を表示するQTreeWidgetを作ってみます。ファイルをFinder/Explorerからドロップできるようにしてみます。ファイル名と、サイズを表示します。残念ながら、QtDesignerで作ったオブジェクトでは無理で、コードでnewしたQTreeWidgetでしか動きませんでした。レイアウトツール上ではそのスペースを適当にあけてレイアウトしておきます。

こちらで解説しているような、ダイアログ表示クラスの中に埋め込むコードを前提としています。UI用のクラスをJSで作って、this.widgetにロードした後に差し込む用のコードです。

this.fileTable = new QTreeWidget();
// 挿入位置はレイアウトによって変えてください
this.widget.layout().insertWidget(0, this.fileTable);
var policy = QSizePolicy.Policy(QSizePolicy.Preferred), QSizePolicy.Policy(QSizePolicy.Preferred);
this.fileTable.setSizePolicy(policy);
// ドロップ設定
this.fileTable.acceptDrops = true;
this.fileTable.dropIndicatorShown = true;
this.fileTable.dragDropMode = QAbstractItemView.DropOnly;
this.fileTable.defaultDropAction = Qt.CopyAction;
// オーバーライドするメソッド
this.fileTable.supportedDropActions = this.supportedDropActions.bind(this);
this.fileTable.mimeTypes = this.mimeTypes.bind(this);
this.fileTable.dropMimeData = this.fileDropMimeData.bind(this);
// その他見た目の設定
this.fileTable.columnCount = 2;
var fileTableHeaderItem = this.fileTable.headerItem();
fileTableHeaderItem.setText(0, qsTr("File Name"));
fileTableHeaderItem.setText(1, qsTr("Size"));
this.fileTable.setColumnWidth(0, 200);
this.fileTable.setColumnWidth(1, 80);

オーバーライドするメソッド定義を3個ほど作っておきます。C++なら事前にQTableWidgetの子クラスを作っておかなければなりませんが、適当な場所に動的に関数を作って差し込めば動いてくれるのは動的言語ならではですね。ここでは、MyDialogクラスのメソッドにしておきます。なぜ.uiファイルから読み込んだウィジェットではダメなのかは分かっていませんが・・・

// この2つの定義は定型文
MyDialog.prototype.supportedDropActions = function ()
{
    return Qt.ActionMask;
};

MyDialog.prototype.mimeTypes = function ()
{
    return ["text/uri-list"];
};
// こちらは実際のコードに合わせてカスタマイズが必要
MyDialog.prototype.fileDropMimeData = function (item, index, data, action)
{
    var urls = data.urls();
    for (var i = 0; i < urls.length; i++)
    {
        var filepath = QDir.toNativeSeparators(urls[i].toLocalFile());
        var fileinfo = new QFileInfo(filepath);
        var treeitem = new QTreeWidgetItem(this.fileTable);
        treeitem.setText(0, fileinfo.fileName());
        treeitem.setText(1, fileinfo.size());
    }
    // これがないとFinderが受け取れなくてファイルを戻すアニメーション
    // を実行する。受け取れない形式だったらreturn falseにする。
    return true;
};

これはExplorerやFinderからファイルをドロップする処理ですが、QTreeWidget内部でのドラッグ・アンド・ドロップも実装できます。まずは設定を変更します。

this.fileTable.dragDropMode = QAbstractItemView.DragDropMode(
    QAbstractItemView.DropOnly,
    QAbstractItemView.InternalMove);

次にドロップ時のコールバックを変更します。コード全体を説明はしませんが、どちらの処理かは最後に紹介したコールバックのactionを見れば判別できます。

MyDialog.prototype.fileDropMimeData = function (item, index, data, action)
{
    if (action === Qt.MoveAction)
    {
        // 外部からドロップ
        return true;
    }
    else if (action === Qt.CopyAction)
    {
        // 内部でのドラッグ・アンド・ドロップ
        // マウスで移動した項目たち
        var movedItems = this.fileTable.selectedItems();
        this.fileTable.clearSelection();
        // 移動先はitemに格納
        var moveTargetItem = item;
        // ここで移動後に行われる処理を書く
        // 最後はreturn trueが必要です。
        return true;
    }
};
posted by @shibukawa at 09:40 | Comment(212) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QTreeWidget (2)

2012年12月08日

Qt+JS: QTreeWidget (1)

GUIでの設計方法を3回にわたって紹介してきました。次は具体的なコンポーネントをいくつか紹介します。まずはよく使う代表的なものとして、QTreeWidgetを紹介します。

ボタンとテキストエリアだけのUIであればブラウザベースでも全然問題ありませんが、数百項目、場合によっては1000件近いツリー要素をハイパフォーマンスで動かせるのは、デスクトップアプリの利点ですよね。ブラウザベースよりも、より複雑なデータを気軽に扱うことができます。GUIツールでレイアウトをしており、treeWidgetという名前で登録されているものとします。

QTreeWidgetで項目を追加するには、QTreeWidgetItemを使います。

// ルート直下にノードを追加
var treeWidget = this.widget.treeWidget;
var item = new QTreeWidgetItem(treeWidget, 10);
item.setText(0, "Hello World");
item.setIcon(0, new QIcon(':/graphics/flower.png'));

ツリーを使って行を足す場合にこのあたりが最低限のコードになるでしょう。最初のコンストラクタでは、表示対象のQTreeWidgetを指定します。これの次の"10"という数値は、省略可能です。ノードの識別を簡単に行うために使うことができます。後から、var type = item.type(); で取得可能です。ただし変更できません。setTextとsetIconの0はカラムのIDです。これは後述します。最後の行でアイコンを設定しています。コロンから始まるパスは、Qtの画像リソースに登録したファイルを参照するための方法です。もちろん、普通のコンピュータ上の画像を指すパスも使えます。

ツリーなので階層にしないと面白くありません。この時は、QTreeWidgetItemの最初のパラメータに、QTreeWidgetの代わりに親となるノードを渡すだけです。他は一緒です。

// 孫の要素を追加
var grandChild = new QTreeWidgetItem(item, 20);
grandChild.setText(0, "Hello World");
grandChild.setIcon(0, new QIcon(':/graphics/flower.png'));

孫から子を参照するにはparent()メソッドでアクセスできます。子から親を参照しようとするとどうなるでしょうか?この場合はnullが帰ってくるので使い分けましょう。

QTreeWidgetの直下にあるノードの一覧の取得する方法は次の通りです。子供から孫へも同じようにchild(n)メソッドで取得できます。ノードはsetHidden(true)で見えなくすることも可能ですが、この方法を使えば非表示でもそうじゃなくてもすべての項目を取得できます。

var topCount = tableWidget.topLevelItemCount;
for (var i = 0; i < topCount; i++)
{
    var node = tableWidget.topLevelItem(i);
}

先ほど、識別のためのデータを設定できると紹介しましたが、変更できませんでした。変更できるデータももてます。JSONモジュールがあるとしたら、次のようなコードが書けます。

item.setData(0, Qt.UserRole, JSON.stringify({name: "Yoshiki"}));

QTreeWidgetは、名前はツリービューですが、行指向のテーブルを表示するのにも使えます。QTableWidgetはセルごとに編集ができるような高性能な部品となっています。その分セルごとにオブジェクトを設定しなければならなかったりと複雑です。こちらは行ごとにしか選択できませんが、その分、1つのQTreeWidgetItemを使えば1行すべての表示がまかなえます。。setText()を必要なカラム番号付きで呼び出せばいいだけななのでテーブルっぽい表示をするのは難しくありません。ここではコードでカラム数を変更していますが、GUIのツール上でも編集できます。

// ルート直下にノードを追加
var treeWidget = this.widget.treeWidget;
// 列が3つになる。
treeWidget.columnCount = 3;
var item = new QTreeWidgetItem(treeWidget, 10);
item.setText(0, "Hello");
item.setText(1, "World");
item.setText(2, "!!);
item.setIcon(0, new QIcon(':/graphics/flower.png'));

駆け足でしたが、かなり高性能なウィジェットであることがわかったと思います。このコンポーネントの使い方が分かるだけでも世界が大きく広がります。このウィジェットはかなり大掛かりなものなので、何回かシリーズで紹介していきます。

posted by @shibukawa at 02:47 | Comment(204) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QTreeWidget (1)

2012年12月07日

Qt+JS: QtDesignerによるレイアウト(3)

部品を並べる時の方法として、QWidget、QFrame、QGroupBox、レイアウトといくつか選択肢があります。どのような基準で使い分けるかを紹介します。

QWidgetとレイアウト

Screen Shot 2012-12-07 at 9.08.22 AM

ツール上はレイアウトは赤枠が表示されますが、プログラム上ではどちらも見た目はほぼ変わりません。QWidgetも内部にレイアウトを持ち、レイアウトを直接置くのと同じパラメータを設定すれば結果は同じです。

レイアウトのメリットとしては、ツリー上に階層にしても、ソースコードから操作する場合は無いものとして扱われる、という点です。つまり「見た目を改善するために、入れ子にしてチェックボックスの横にラベルを追加したよ」という場合も、ソースコードを修正する必要はありません。コードに影響を与えずにちょっとした修正ができるので使えるところはレイアウトを使ったほうがいいでしょう。下記のレイアウトにはボタンが2つありますが、プログラムからは、両方共、"Parent"と書かれたWidgetの子供に見えます。

Screen Shot 2012-12-07 at 9.14.20 AM

QWidgetにもメリットはあります。QWidgetに乗っている複数の子供のウィジェットをまとめてvisible = falseしたり、enabled = falseしたり、ステータスを一括で変更する場合に便利です。

QFrameとQGroupBox

Screen Shot 2012-12-07 at 9.07.35 AM

枠です。どれも枠です。QGroupBoxはflatというオプションを入れると見た目が左下のようになります。QFrameも線の種類をいくつか選べるようになっています。基本は好みで選べばいいと思います。

ラベルを入れたい場合はQGroupBox、いらない場合はQFrame。タブの中とか枠線が多すぎてうるさそうならFlatのQGroupBoxとか、そんな感じで使ってます。FlatじゃないQGroupBoxも入れ子になったり、たくさん並ぶとちょっとうるさい感じがしますね。

たまに部品が多くて小さい画面だと厳しそうだなー、と思う時はQScrollAreaを代わりに使うこともあります。

このあたり使い分けられるようになると、「おれデザイン作っている感」が味わえるようになります。

posted by @shibukawa at 09:34 | Comment(205) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QtDesignerによるレイアウト(3)

2012年12月06日

Qt+JS: QtDesignerによるレイアウト(2)

QtDesignerによるレイアウトで、おや?と思うケースがいくつかあったりします。

レイアウトが設定できない?

コンテナ要素は最低1個でも何かウィジェットが置かれないと、レイアウト設定が選べません。

ドラッグ&ドロップではインジケータに注目

Screen Shot 2012-12-06 at 8.21.22 AM

何層も階層になってくると、部品をぽんっと置いても、思ったのと違うところに置かれてしまうことがあります。今カーソルがある位置は次の2つの情報から読取ることができます。特に、親ウィジェットが子供を持ってなくて、小さくリサイズされてしまっている場合などに分かりにくかったりします。

  • 置こうと思っているコンテナ要素・レイアウトがハイライトされて色が変わる
  • 青いカーソルが出る(レイアウトが設定されていて、同じ階層にすでに部品がある場合)

この隙間に部品を置きたいのだけど、青いカーソルが出ない!

Screen Shot 2012-12-06 at 8.24.22 AM

例えば2つグループボックスがあって、この隙間にもう一つ入れたいとします。置きたいのは、グループボックスが置かれている親のWidgetです。ですが、操作してみると、インジケータはグループボックスにしか合ってくれず、親のWidgetには合ってくれません。

この場合は、一時的に親のWidgetのレイアウト設定をいじって、隙間を大きくします。間に入れるときはlayoutSpacingで隙間を、上下左右に差し込みたい場合は、layoutTopMarginなどのマージンを操作します。

Screen Shot 2012-12-06 at 8.24.11 AM

カーソルが出てきました!部品を置いたら、忘れずにレイアウトを戻しましょう。コンテナ系は上下左右の隙間のデフォルトが12になっているので、上下左右に入れるのはそんなに困らないのですが、Layout欄にあるシリーズは隙間がデフォルトがゼロなのでこの操作が必要になります。

Screen Shot 2012-12-06 at 8.26.22 AM

部品のコピー&ペースト

Screen Shot 2012-12-06 at 8.30.23 AM

QtDesignerで部品をコピペしようとすると、このダイアログが出ることがあります。ようするに、レイアウトが設定されているところには置くことができませんよ、ということです。この場合は、いったんBreak Layoutを選んでフリーレイアウトにしてからペーストすればOKです。ただし、レイアウトを変更すると、マージンの値などのレイアウトに設定していた値はクリアされてしまうので要注意です。

Screen Shot 2012-12-06 at 8.32.23 AM

タブ・スクロールでレイアウト設定が出ない

Screen Shot 2012-12-06 at 9.08.02 AM

Tab Widget, Scroll Areaなどのコンテナ要素を置くと、最初から、tab, tab_2, scrollAreaWidgetContentsといったオブジェクトが作られます。ツリーで見ると、あたかもこれらの子供のオブジェクトがそれぞれレイアウトを持っているように見えます。実際にそうなのですが、レイアウト設定の勝手がちょっと異なります。

Tab Widgetを例に説明します。まずは、子供のタブに孫ウィジェットを置きます。その後、親のTabWidgetを選択して、レイアウトを設定します。そうすると、現在アクティブな子どものタブのレイアウトが設定されます。選択対象(TabWidget)と、変更対象(アクティブな子供)が違うのはやや違和感がありますが、そういう仕様なので仕方がありません。

アクティブなタブページの情報も保存される

地味であまり実害は大きくないのですが、タブが5枚ぐらいおかれている設定ウィンドウがあったとします。4ページ目のタブにボタンとラベルを追加してその場で保存、アプリ起動してみると、最初のページが4ページになってしまいます。タブなどを操作した場合は、忘れずに最初のページを選択してから保存しなければなりません。

posted by @shibukawa at 09:17 | Comment(275) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QtDesignerによるレイアウト(2)

2012年12月05日

Qt+JS: QtDesignerによるレイアウト(1)

ガンガンGUIを作っていく時には、QtDesignerを使うのが便利です。Qtの場合はソースコードを使って一からGUIを作り上げていくことも可能ですが、ビジュアルなツールを使っている方が、ちょびっとツールを勉強したUIデザイナーさん(いれば)が、文言やアイコン、レイアウトの微調整をしたりしてくれることもあります。また、ラフなプロトタイプ作成にも良いですし、全体像がツールでつかみやすいので、複数人で仕事をしていて、一つの画面を複数人が修正する可能性がある場合もビジュアルなツールがオススメです。

逆に、エンジニアしか修正しない場合、画面ごとに担当が完全にわかれている場合などはソースコードでもいいと思います。また、一部をGUI作成ツールで作って、ソースコードベースのレイアウトと組み合わせていくことも可能です。また、注意点としては、GUIツールでは提供されていない部品があったり、ツールを作っておいたウィジェットでは使えない機能が少しあったりします(protectedメソッドのオーバーライドとか)。

QtCreater、QtDesignerを起動したら、QtDesignerのFormを選択します。後はファイル名や置き場を決めて行きます。プロジェクトを作っている場合には、最後にプロジェクトへの登録、バージョン管理を使っていればそれらへのファイルの登録も行えます。

Screen Shot 2012-12-05 at 1.17.07 AM

このようなレイアウトツールが起動します。操作性は基本的にはVisual Basic / Delphi / C++Builderなどと同じですが、コードはここからは書きません。あくまでもUIを作るためのものです。

Screen Shot 2012-12-05 at 1.20.04 AM

手順としてはだいたい次のような順番で繰り返していけばいいと思います。

  • 目に見えるContainer要素と、縦横に伸びる大きな要素を入れていく
  • ボタンなどの小さいウィジェットをContainer要素の中に並べる
  • Layout設定を設定してきゅっと締めたり、伸びを調整したり
  • ウィジェット類のプロパティの設定をする

目に見えるContainer要素と、縦横に伸びる大きな要素を入れていく

Screen Shot 2012-12-05 at 7.53.20 AM

並べるときは左側のツールボックスからドラッグしてくればウインドウの絵の中に置くことができます。たまに僕の環境だとツールボックスのドラッグの挙動がおかしくなって使えなくなりますが、その場合はQtDesignerを再起動する必要があります。

QGroupBox(枠とタイトル付き)、QFrame(枠付き)、QTabWidgetが目に見えるContainer要素です。まず全体像を想像しながら、これらの要素を置いておきます。

大きな要素も、GUIの大部分を占める要素ですので、これもどんどん並べていきます。ItemWidgetsのカテゴリのコンポーネントとか、ブラウザコンポーネントとかがこれに該当します。TreeとTable、Listは2種類ずつありますが、動的言語の実装のしやすさを考えると、オススメはItem-Basedの◯◯Widgetの方です。

ボタンなどの小さいウィジェットをContainer要素の中に並べる

Screen Shot 2012-12-05 at 7.56.46 AM

次に、ボタンやラベルなどを並べていきます。右側のツリー構造も確認し、変な親子関係になっていないかも確認しましょう。また要素の名前もきちんと設定します。これらの階層や名前はコードからUI部品にアクセスする上で大切です。コード上で部品を置く箇所には、QWidget(枠線を表示したいときはQFrame)などを置いておくと良いです。

Layout設定を設定してきゅっと締めたり、伸びを調整したり

Screen Shot 2012-12-05 at 7.58.32 AM

次にレイアウトを設定していきます。Qtの場合、Container要素はすべて「レイアウト」を設定できるようになっています。レイアウトをHorizontalにすると、すべての子供の要素が水平に並びます。要素を選択して(ツリーでも部品が並んでいるビューでもどちらでも)右クリックをすると、一番したにレイアウト選択が出てきます。グリッド、縦、横などを駆使して、レイアウトを作っていきます。レイアウトは右側のツリーで見ることができます。☓じるしがなくなるまで設定していきます、次に大きさの計算をするための各種情報を入力していきます。Layoutの項目にある各種部品を使うと、レイアウトを階層化して複雑なUIを作成することができます。例えば、基本はグリッド状に要素を並べていきたいけど、特定のセルだけウィジェットを複数個並列に置きたい場合には、Horizontal Layoutを入れ子状に置いてレイアウトします。レイアウトはQtでは大事な概念なのでインターネット上でもたくさん解説ページが見つかります。

空白があいてしまって間延びするときは、Spacerを入れます。これできゅっと締まります。図の右下のバネみたいなのがSpacerです。Treeのウィジェットとか、大きいコンポーネントがないときはたいていゆるゆるなのでSpacerを入れると良いです。minimumSizeとかmaximumSizeをいじって微調整すると、リサイズしたときにおかしなことになったりするし、他の要素を足したりして変更するときに面倒になるので、これらは最終手段と考えた方がいいです。ウィジェットを数十個並べたとしても、多くても1個か2個だけ設定するだけで済むはず。それ以上設定したくなっちゃうときは、レイアウト関係のコンポーネントやそちらの設定をいじる方が正解となることが多いです。

ウィジェット類のプロパティの設定

Screen Shot 2012-12-05 at 8.18.28 AM

最後にコンポーネントのプロパティを修正していきます。値が固定のコンボボックスの要素を設定したりとか、読み込み専用フラグを立てたり・・・

これらのステップを繰り返してよりよいものにしていきます。一回ではキマらないと思いますので、何度も何度も繰り返すことになるでしょう。また、実際にコード部分を書いて動かしてみると、また調整したくなります。以下の状態がゴールです。例え固定サイズのウインドウだったとしても、可変サイズのつもりで設計しておく方が、、ちょっと部品を追加したくなったときの修正がラクですし、見た目も良くなることが多いのでオススメです。

  • コードで追加するコンポーネントを除いて、他の部品が置いてある
  • コードで追加するコンポーネント用のQWidget/QFrameを除いて、すべてのレイアウトが設定してある(右側ツリーの赤丸がない)
  • 大きなコンポーネントがなくてゆるいところにはSpacerが置いてきゅっとしてる。
  • デザイナー上でリサイズしてみてもおかしなことにならない。
  • コードから値を取得したり、イベントを設定するコンポーネントにきちんと名前をつけている
posted by @shibukawa at 08:13 | Comment(282) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QtDesignerによるレイアウト(1)

2012年12月04日

Qt+JS: 数値を入力するには?

ビルドの仕方、Qtライブラリを組み込んだJS環境の作り方、ドキュメントの見かたまで説明してきました。そろそろ具体的なTipsに入っていこうと思います。

数値入力にはどのウィジェットを使うのがいいのでしょうか?QLineEditを使って編集されたら数値に変換するというのはどうでしょうか?フォームにQLineEditの部品が置いてあるものとしてサンプルを書きます。

this.lineEdit = this.widget.lineEdit;
this.lineEditChanged = function ()
{
    this.lineEdit.textChanged.disconnect(this.lineChangedHandler);
    var value = Number(this.lineEdit.text);
    this.lineEdit.text = value;
    this.lineEdit.textChanged.connect(this.lineChangedHandler);
}
this.lineEditChangedHanlder = this.lineEditChanged.bind(this);
this.lineEdit.textChanged.connect(this.lineChangedHandler);

イベントの中で無駄にイベントが発生しないように一度イベントを切ってから値を変更しています。バリデータを使う方法もあります。

this.lineEdit = this.widget.lineEdit;
var validator = new QRegExpValidator();
validator.regExp = new QRegExp('0|^[1-9][0-9]*$');
this.lineEdit.setValidator(validator);

もちろん、最初から特定のフォーマットのみを扱う別のウィジェットもあります。QSpinBoxです。小数を扱えるQDoubleSpinBox、時間入力のQDateTimeEditもその仲間です。

this.spinBox = this.widget.spinBox;

最後が圧倒的に短いですね。もちろん、最初からこれが使えたらこれしかないのですが、微妙な制約で最短距離を薦めなくて迂回せざるを得なくなるのがGUIプログラミングでよくあることなので、他のも存在を知っておくのも悪くないです。

QLineEditの自力方法のメリットとデメリットは:

  • ◯: どんな複雑な、条件や状態を持つようなバリデーションであっても書くことができる
  • ◯: 空白状態を実現できる(iTunesの曲名入力で、複数の曲を選択して、それぞれの曲の情報が一致しなかった時、みたいな)
  • ☓: 長い

QLineEditのバリデータ方法のメリットとデメリットは:

  • ◯: 正規表現で実現できる範囲で制御できる
  • △: 空白状態を実現できる(空白条件もバリデーションに入れる必要あり)
  • ☓: 範囲指定を正規表現で書くのが面倒
  • ☓: やや長い

専用の入力ウィジェットのメリットとデメリットは:

  • ◯: 短い
  • ◯: 値の範囲などの指定などが便利
  • ◯: 値を変更するボタンが付いている。増減量も設定可能。
  • ◯: pxなど、単位などの文字を前後(prefix, suffix)に追加することも可能。
  • ☓: 空白条件が設定できない。ドキュメントを見るとできそうだけどできなかった・・・
posted by @shibukawa at 09:04 | Comment(245) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: 数値を入力するには?

2012年12月03日

Qt+JS: ドキュメントの読み替え方

QtをJSから使う場合、C++版Qtのドキュメントを読み替えながら使うことになります。これはきっと他言語のバインディングからC++のヘビーなライブラリを使う場合(Qtだけじゃなくて、GTKとか、wxWidgetとかも)も同様かと思います。当然C++は他の言語にない特徴をいくつか持っているため、そのまま利用できないケースもあります。

QComboBoxを例にして説明します。

まず、publicなメソッドと、publicなシグナルはそのまま使えます。

// publicなメソッド
comboBox.addItem("Times New Roman");
// publicなスロット
comboBox.clear();

publicなプロパティは関数呼び出しではなくて、値を直接代入したり取得して使います。プロパティと似たような働きのシグナル等(enabledに対する、setDisabled)が提供されていることもありますが、値の取得との対称性を考えると、なるべくプロパティの方を優先して使う方が読みやすいコードになると思います。これはJSに限った話じゃなくてQt全般に言えることかも。

// 取得
var index = comboBox.currentIndex;
// 設定
comboBox.enabled = false;

publicなシグナルはこんな感じで使います。他にもメソッドがあるのかな・・・今のところ使っているのはこのあたりのみ

// 無名関数を渡す。
comboBox.editTextChanged.connect(function () {
   // 処理
});
// thisを指定して渡す。
comboBox.editTextChanged.connect(this, this.onChanged);
// bindして渡す。パラメータを任意個追加できる。
var handler = this.onChanged.bind(this, "param");
comboBox.editTextChanged.connect(handler);
// bindしたやつのみ、disconnectできる
comboBox.editTextChanged.disconnect(handler);

QStringを受け取るものはJavaScriptの文字列、QStringListを渡すものはJavaScriptの文字列配列でOKです。

comboBox.addItems(["Times New Roman", "Courier New"]);

引数違いで多重定義されているシグナルは以下のように呼び分けます。あまり美しくないけど仕方がないですね。

// int版
comboBox["currentIndexChanged(int)"].connect(handler);
// QString版
comboBox['currentIndexChanged(QString)'].connect(handler);

enum値の渡し方はちょっと特殊です。ドキュメントのMember Type Documentationと書かれたところの名前(enum QComboBox::SizeAdjustPolicy)と、表中のConstantの列の名前が大事です。enumのグループ名の関数に、定数を渡します。可変長引数の関数なので、複数個の値のORを渡したい時は、全部この関数に渡します。大体長い行になってしまいがちですが・・・

var policy = QComboBox.SizeAdjustPolicy(QComboBox.AdjustToContents);
comboBox.sizeAdjustPolicy = policy;

protectedなオーバーライドするメソッドも利用できますが、これについては別の日にpaintEventのオーバーライド例を紹介しようと思います。QtDesignerで作ったuiファイルに書かれているコンポーネントを後からメソッドだけ差し替えてもうまく動きません。

posted by @shibukawa at 09:12 | Comment(171) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: ドキュメントの読み替え方

2012年12月02日

Qt+JS: QtDesignerダイアログを表示する

前回のエントリーのQtのクラスをJSから触れるようにするで、QtのクラスがJSが使えるようになりましたので、ダイアログを表示します。Qtのクラスはすべてグローバルに置かれているので、PySideやPyQtに慣れている人は戸惑うかもしれません。

QtにはGUIをグラフィカルに設計するツールがあります。単体のツールになっているQtDesignerと、統合ツールのQtCreatorです。まあどちらもGUI作成に関しては同じです。ツールを使って.uiファイルを作成します。作成するのはQWidgetとします。スクリーンショットはめんどうなので、後回しにしますが、Root直下にボタン(QPushButton)が2個、もしくはRoot直下にレイアウトを置いてボタンが置かれているものとします。名前はdoButton, closeButtonとします。あと、こちらのCommonJSスタイルのrequireが使えるようにしてあるものとします。

// MyDialog.js
var MyDialog = function ()
{
    QDialog.call(this);

    var layout = new QGridLayout();
    var loader = new QUiLoader();
    var file = new QFile(__dirname + '/../dialogs/MyDialog.ui');
    if (file.exists())
    {
        if (file.open(QIODevice.ReadOnly))
        {
            this.widget = loader.load(file);

            // つけた名前でアクセスできる
            this.doButton = this.widget.doButton;
            this.closeButton = this.widget.closeButton;
            // こんな感じでシグナルを使う
            this.doButton.clicked.connect(this, this.onDoButtonClicked);
            this.closeButton.clicked.connect(this, this.onCloseButtonClicked);
            layout.addWidget(this.widget, null, null);

            file.close();
        }
    }

    this.setLayout(layout);
};

// 継承
MyDialog.prototype = new QDialog();

MyDialog.prototype.onDoButtonClicked = function ()
{
    // プロパティへのアクセス。代入で行けます。
    this.doButton.text = "Button Clicked";
};

MyDialog.prototype.onCloseButtonClicked = function ()
{
    this.done(QDialog.Accepted);
    // もしくは
    this.done(QDialog.Rejected);
};
exports.MyDialog = MyDialog;

このコードを使う場合は:

var MyDialog = require('MyDialog').MyDialog;
var dialog = new MyDialog();
if (dialog.exec()) // doneにAcceptedが渡されると真
{
    // Closeが押された後の処理
}

このコードはそんなに長くないですが以下の要素が含まれています:

  • Qtのクラスへのアクセス
  • Qtクラスの継承
  • フォームのロード
  • フォームの要素のウィジェットへのアクセス
  • シグナルとプロパティの利用
posted by @shibukawa at 09:04 | Comment(215) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QtDesignerダイアログを表示する

2012年12月01日

Qt+JS: QtのクラスをJSから触れるようにする

QtではJavaScriptを使ってコードを書くこともできます。詳しくはこちら参照。ベースはC++で、QtScriptエンジン(JavaScriptエンジン)を動かします。これはPureなECMAScriptのエンジンで、追加のコンポーネントとかは一切ないのですが、C++からクラスとか関数を登録できます。QtScriptBindingGeneratorで作ったバインディングを実際に使えるようにします。

なお、現在のQtScriptBindingGeneratorはQt4系にしか対応していません。Qt5はまだダメでした。

まず、QtScriptバインディングのファイルをplugins/scriptフォルダに置きます。ビルド時にこれらのファイルもデプロイされるようにプロジェクトファイルに追加します。

folder_01.source = js
folder_01.target = .
folder_02.source = plugins
folder_02.target = .
DEPLOYMENTFOLDERS = folder_01 folder_02

これらのバインディングを実行時に使えるようにするには、もろもろの設定をする必要があります。ちょっと長いですが、基本は「アプリケーションのsetLibraryPathsで作ったバインディングを読みこませる」「QScriptEngineでimportExtensionsして、Qtのクラスを登録する」の2点です。

QDir pluginDir(QApplication::applicationDirPath());
#ifdef Q_OS_MAC
pluginDir.cdUp();
pluginDir.cd("Resources");
#endif
if (!pluginDir.cd("plugins")) {
    fprintf(stderr, "plugins folder does not exist -- did you build the bindings?\n");
    return(-1);
}
QStringList paths = app.libraryPaths();
paths << pluginDir.absolutePath();
app.setLibraryPaths(paths);

QStringList extensions;
extensions << "qt.core"
           << "qt.gui"
           << "qt.xml"
           << "qt.svg"
           << "qt.network"
           << "qt.sql"
           << "qt.opengl"
           << "qt.webkit"
           << "qt.xmlpatterns"
           << "qt.uitools";
foreach (const QString &ext, extensions) {
    QScriptValue ret = engine.importExtension(ext);
    if (ret.isError())
    {
        qDebug() << "Error occured to load extionsion: " << ret.toVariant() << ext;
    }
}

これで、QScriptEngineに渡すスクリプトファイルから、Qtの機能にアクセスすることができます。基本的にはC++のライブラリリファレンスを見てもらえばほぼそのまま使えるのですが注意点も少々あったりします。

  • 使えないクラスもたまにある。ファイルシステムをツリービューで見せるコンポーネントとかなかった。
  • QStringの代わりに素のJSの文字列が使える。
  • QStringListとかは、素のJSの配列に文字列を入れて渡せば良い。
  • 日付オブジェクトの代わりに、素のJSのDateオブジェクトが返ってくる。
  • オーバーロードされているメソッド名が変わる点に注意。
posted by @shibukawa at 11:19 | Comment(141) | TrackBack(0) | 日記 はてなブックマーク - Qt+JS: QtのクラスをJSから触れるようにする

2012年09月30日

Pythonはなぜ?str.join(seq)なのか?

Screen Shot 2012-09-29 at 10.13.21 AM

PythonのAPI設計の中で、たまに思い出したように話題が出てくるのが、配列に入った文字列を結合するメソッド。Pythonではstr.join(iterable)です。他の言語(僕がよく知っているRubyとJavaScript)はArray.join(String)となっています。どちらでもありえる話ですが、個人的にはPythonの方が自然だな、と感じていました。ですが、他の言語の方がいいという人も多く、Pythonプログラマーの中でも好き嫌いが出たりもします。せっかく、弾さんがPerlの国からやってきて適度にガソリンをまいて炎上したところなので、Pythonの歴史を紐解いてみました。

軽くjoinの歴史について語っているサイトはないか探してみる

軽くぐぐってみると、何箇所か言及しているところがありました。

まずは無料のPython教育資料のDive Into Python。1.14. Joining lists and splitting stringsの項目の中に、歴史に関するメモ(Historical Note)という欄があります。ここによると:

  • 1.6以前のPythonの文字列には便利なメソッドがなかった(実際、配列に毛が生えた程度)
  • 文字列操作はstringというモジュールをimportして行っていた
  • 2.0で文字列のメソッドが強化された時に他のモジュール関数と一緒にstring.joinも文字列のメソッドになった
  • 当時はハードコアなPythonプログラマでもこれに反対(配列に入れるべき)の人がたくさんいた

他には、Stack Over FlowのPython join, why is it string.join(list) instead of list.join(string)?というスレッドもひっかかりましたが、この中で技術的に語っているのもありました。

  • リストやタプル、ジェネレータなど、いろんなシーケンスに対応する必要がある
  • 文字列、バイト列など、いろいろな対象があり、対象ごとに処理が変わる

それに対して、それならシーケンスの共通親クラスから対象のjoinを呼べばいいだけやんか!とツッコミが入っています。まあこのツッコミでは足りないのですが、元の回答も足りないのは確かです。どちらの回答者も、逆転裁判をプレイして論理思考を訓練すべきですね。

補足

@atsuoishimotoさんより、Pythonは2.2まではCで書かれた組み込みクラスの継承はできなかったとのコメントがありました。たしかにそうだった。

これは多重ディスパッチと呼ばれる問題の1つです。2種類のクラス群が関係しています。シーケンスのクラスがn個あって、文字列の種類がm個あれば、n×m個の組み合わせがあります。大抵の場合は、nとmのうち、変化の少ない方、あるいは数が少ない方のメソッドとして実装する、あるいはまったく属さないで独立の関数として実装する方法が取られますが、まあどちらに属させても正しいかどうかは状況による、といった感じです。後者の場合はパターンマッチ(関数型言語)やオーバーロード(C++)などの言語機能とセットになりますが、Pythonなどの動的言語にはそれらの言語機能がないので、前者の実装となります。

いろいろ見てみましたが、状況が分かっただけで、「なぜPythonがこうしたのか?」の手がかりはまだ得られていません。ここは本丸を攻めるしかありません。敵はpython.orgにあり!

PEPを見てみる

続きを読む
posted by @shibukawa at 02:31 | Comment(42) | TrackBack(0) | 日記 はてなブックマーク - Pythonはなぜ?str.join(seq)なのか?

2012年09月28日

Adobe Edge Animateの今後期待できる用途

さきほどのブログエントリーはあくまでもFlashの代替と考えた場合のお話でした。Flashはあくまでも枠の中で動かす的な用途が多いのですが、Edge Animateは「枠を作る」用途で使えそうな気がします。

アプリケーションの枠を作るのに必要な機能

例えば、HTMLベースのメールアプリを作るとして、ログインフォームが出て、そこからメール一覧をとってきて、メールのリストを表示するといったケースを考えてみます。今後数年間のトレンドを先取り・・・かは分からないですが、ログインフォームの表示、認証待ち、クローズ、メールのロード、リストの表示などなど、さまざまなアクションにアニメーションをつけるといったことがしたくなるでしょう。今までのWebアプリよりももっと動的に動いて見えるアプリ。Qtなどでは作りにくいような遷移を伴ったアプリです。あるいはウィジェットが満載の(iGoogleのようなアプリ)などです。こういったものを作る上で、Edge Animateが活躍しそうです。

Edge Animateの各要素はすべてHTMLのタグになります。idが標準で付きますし、classも設定できます。テキストであればdivタグ以外もいろいろ選択できます(pタグとかh1タグとか)。現状でフォームを作成する機能はないのですが、そこはDjangoのフォーム作成などを利用して、フォームをAjaxで送ってタグの中に差し込めば、全体のレイアウトをEdge Animateで構成することが可能になります。

ドラッグ・アンド・ドロップでウィジェット(シンボルで表現)を整列するような機能をEdge Animateで作りこんで、それをアプリケーションのテンプレートとして配布すれば、誰でも似たような高機能なウェブサイトが作れるようになりそうです。JavaScriptの世界はどちらかというと「部品」がライブラリだったのですが、ウインドウマネージャのような仕組みをライブラリとして作って配布、みたいな感じですね。

また、シンボル単位でエクスポートすることもできるので、JavaScriptでいろいろ作りこんでそれ単位で配布することが可能です。jQueryも使えるし、ツリービューアーとかそういう部品として配布できそうです。jQueryのプラグインの場合、関数として定義して使う形式になりますが、Edge Animateでは、よりコンポーネントに近い形式で作り込んで配布が可能です。

今後増えて欲しい機能

より高度なCSSが設定できるようになればいいな、と思います。ボーダーとかグラデーションとか、もっと自由に設定できるようになると良さそうです。まぁ、CSSでいろいろやりすぎると今のモバイルのブラウザのパフォーマンスが良くないということであえて入れてないのかもしれませんが。現在は各要素がデザインを持っていて、CSSのようにclassでデザイン指定がないのですが、そのあたりもできるようになると良いかな、と。特にAjaxでフォームを差し込んだりするのであれば、フォームのデザイン機能は欲しいですよね。グローバルなJavaScriptのファイルのロードとかも今はどこでやればいいのか見当たらないです。ウインドウシステムのように使うのであれば、9パッチのようなものが簡単に作れると捗りそうです。

後はエクスポートするときにCSSスプライトが生成されるよ!とかになると面白そうです。

とは言え、現状でも、進撃のバハムートやファイナルファンタジーブリゲード的なミッション画面や合成画面っぽいUI(画像でウインドウとかボタンを作る)とか、カードゲームの管理画面とかを作りこむには十分な機能を持っていますし、ソーシャルゲーム的な世界から積極的に活用されるようになる可能性もありそうな気がします。

なんにせよ、いろいろ用途が広がりそうですし、将来が楽しみなツールに思えました。

posted by @shibukawa at 00:50 | Comment(28) | TrackBack(0) | 日記 はてなブックマーク - Adobe Edge Animateの今後期待できる用途

2012年09月27日

Adobe Edge Animate 1.0を試してみた

Screen Shot 2012-09-26 at 7.19.42 PM

HTML5は、HTML5という名前のくせに98%ほどはJavaScriptという、詐欺っぽい名前でありながら一世を風靡したとおもいきや、FacebookのCEOの発言で一悶着あったりと、まだまだいろいろな話題を提供し続けてくれています。個人的にはGPUサポートやスマートフォンの高速化などがこなれてくれば、さまざまな用途で活用できるようになるだろうな、と思っています。HTMLのレイアウトがGPGPUとかで行われるようになれば、CPUでレイアウトを処理している今時のGUIツールキットよりも高速に動くようになる時代が来てもおかしくないですしね。今はまだまだHTML 5に投資し続ける時ですよ!バカ発見器のTwitterのTLになんとなく踊らされた人たちが寝転んでいる今がチャンスです。

そんな中、アドビ社がAdobe Edge Animate 1.0を無償提供することを発表しました。Flash四天王のうちの最弱なモバイル端末のFlash Playerはやられてしまいましたが、なんだかんだでFlashとAdobeの影響力はまだまだ強いな、と感じています。ゲームエンジンとしてしのぎを削っているUnreal EngineとUnity 3DはそれぞれFlash向けのエクスポータを開発中です。10年近くパフォーマンスチューニングされ続けたFlashは、マルチプラットフォームなブラウザ用のVMとして強力ということでしょう。AAAタイトルのゲームのエンディングのロールを見ると、だいたいScaleFormという文字が出てきます。これはゲームコンソールやモバイル端末用の特殊なFlashプレーヤーです。インタラクティブなメニューやちょっとしたカットシーンはFlashが活用されているということです。AIRもスマートフォン向けのアプリ開発環境として変換ツールが開発されていますし、インタラクティブなアート作成環境として、一定数のスキルをもったデザイナーさんが確保できるツールはFlash以外は見当たりません。

HTML5、とりわけCSS3がFlashキラーといっても、デザイナーさんがFlashのように自在に使えるツールの決定版は今まではありませんでした。Sencha Animatorとかはありましたが・・・本とかもFlashほどは見かけないですよね?僕自身、Adobeのツールの中で一番使い方が分かっているのがFlashなので(5, MX, CS5と来て、ほぼマクロメディア時代の知識ですし、教わったわけではないので勘違いしているところもあると思いますが)、数時間触ってみて分かる範囲でFlashとの比較をしてみようと思います。作った絵にセンスがなくてすんません。

Edge Animate 1.0とFlashで大きく変わったところ

続きを読む
posted by @shibukawa at 16:13 | Comment(88) | TrackBack(0) | 日記 はてなブックマーク - Adobe Edge Animate 1.0を試してみた

2012年09月18日

オンラインの議論にはTwitterは適さないというけれど

では、どのようなシステムならいいのかなー、と考えてみる。ダメだというのは簡単だけど、ダメなら自分の頭で代替案を考えてみるのが俺のジャスティス。というのはどうでもよくて、Python-devのMLの1999年当時のstr.join(seq)のスレッド追いかけんのめんどくさいよ(# ゚Д゚) ゴラァというところがスタートなんだけど。

  • オーガナイザーがいる。議論の議事進行役。編集長。
  • 議論への参加にはオーガナイザーの承認がいる。
  • 意見を言う時は次のどれかを選ぶ。
    • 前に出ている意見に対する賛成(いいね的でコメントは不可)
    • 矛盾の指摘(反証が必須)
    • ゆさぶり(その意見ではうまく説明できない箇所・足りない所についての追加説明要求)
    • 議題の追加(オーガナイザーの承認必須)
  • 議論として成り立たないようなコメントがある場合はオーガナイザーが却下することができる(却下の理由とともに却下した事実は残る)

うむー。まるで逆転裁判のようだ。

Open IDとか使えばユーザ管理というか、Twitterの議論から移行してくることは可能だろうし、ある程度Twitter上で行われているお話をオーガナイザーがTogetter的にまとめて、そこを出発点に議論する、というのも手ではあると思う。そして最後に議事録として議論の見える化ができて、PEPドキュメント化されれば完璧。ゆさぶりで出てきた事実は、ゆさぶりの親コメントにマージしてやれば、基本的には反証→反証というきれいな議論の流れになると思う。Twitterの場合は言い逃げもできて良い感じに議論を消滅させるというか、無視するということを使うことで、徹底的な殴り合いをしなくてもいいメカニズムなので、この流れで議論するのは最初からある程度仲がいい人じゃないとダメだろうな、という気はするけど。

誰か作ってくれないかなー

posted by @shibukawa at 23:32 | Comment(25) | TrackBack(0) | 日記 はてなブックマーク - オンラインの議論にはTwitterは適さないというけれど

2012年09月15日

アジャイルの「ア」は合気道の「ア」

Sensei Fujita
taken by denisko under CC BY-NC-SA

今年はサンフランシスコにいて、かつ先月子供が生まれたばかりということもあって、日本にふらっと行ってXP祭り2012に参加することができないので、今年はビデオレターで出演することになりました。僕が考えるアジャイルの核について話をします。ビデオレターって反応がないから難しいですね。なにか間違ったことを言ってしまって(たぶん色々間違っている)も「あ、今間違えました」って気付けない。ビデオレター達人になるにはどうすればいいんでしょうね?手元のNikon D3100+NIKKOR 35mmでFull HDで動画を撮ってみたので、絵は綺麗に撮れたと思いますが、なんか声が小さそうなのでブログにも書きます。XP祭り参加する方はまだ見ないでー!いろいろ補足もしていこうと思います。あと、時間的な制約で2/3ほど内容を削ったので、このブログにはそのあたりも含めます。ぜひ、懇親会でハッスル(死後)した後にお読みください。

日本のアジャイルの黎明期と、アジャイル関連のイベント

僕がアジャイルのコミュニティに関わって10年以上たちました。XP祭りも最初が2003年だったので今年で10回目ですよね。昨年のXP祭りでは10年前のアンケートの結果を紹介しながら話をしましたが、10年前はアジャイル導入は夢の話でした。アンケートを取っても、ユニットテストとリファクタリングだけはやってみた、というレベルの人が多かったように思います。

でも、アジャイルの夢は覚めることなく、時には会社を動かした人がでたり、世界の勉強会に出張で行かせてくれたり、あるいは転職しちゃった、と夢を叶える人もでてきてます。僕も当時は東工大で、その後周りがトヨタトヨタと騒ぎ始めたので、反骨精神が目覚めてホンダに就職し、その後はDeNA、現在は子会社のngmoco:)でなんだかんだでアジャイルっぽい環境に落ち着いています。「ヘイ、ヨシキ!スクラムって知ってるか?」「最初のスクラム本の日本語訳はやったよ」的な会話もキメました。いろんな時差をまたいでいるので教科書通りじゃないですがー。いつかこのあたりの話もしたいですね。

適用が難しいと言われながら、多くのエンジニアを惹きつけて、ゲリラ活動を行わせて世界を変えてしまう。アジャイル原理主義教団は危険だ!今すぐクラス名を記号+数字にして奴らの言論を封じろ!みたいなプレゼンもかつて行われたぐらいです(by牛尾さん)。アジャイルの何が魅力的なんでしょうか?

あと、今日のXP祭りもそうですが、アジャイルのイベントではアジャイルの本に必ずしも書いていない話題もたくさんあります。初期のころのイベントで言うと、マインドマップ、コーチング、パタン・ランゲージ、トヨタ生産方式、振り返り、制約理論、アジャイルUXなんてのも出てきました。パターンそのものはXPの記述には使われていますが、パタン・ランゲージそのものに興味を広げて、沢田マンション(Google日本語入力で補完が出た!)に行っちゃう人も出てきたのはケント・ベックもあずかり知らぬところだと思います。

アジャイルイベントの多様なセッションとアジャイルの共通点

続きを読む
posted by @shibukawa at 01:35 | Comment(58) | TrackBack(0) | 日記 はてなブックマーク - アジャイルの「ア」は合気道の「ア」

2012年08月13日

子供が産まれました

DSC_0995

もう一週間たってしまいましたが、サン・フランシスコのCalifornia Pacific Medical Centerで長女が産まれました。予定日から一週間近く遅くの出産で、生まれる前から嫁から引きこもり扱いされたりしていましたが、おめめがぱっちりした子が無事産まれました。母子ともに健康です。初産で海外で出産というのはチャレンジングでしたが、いろいろな方のサポートのもと、無事に安心して出産を迎えることができました。うちの母親もこちらまで来てくれました。とても穏やかな子で、お腹すいても、おむつが濡れてもほとんど泣かない子で、授乳の合間は良く寝ています。

ちなみに、結婚のきっかけとなった、ソニックの音楽のディレクターの瀬上純さんとは、一日違いの誕生日となりました。

アメリカでの出産

続きを読む
posted by @shibukawa at 12:15 | Comment(77) | TrackBack(0) | 日記 はてなブックマーク - 子供が産まれました

2012年07月27日

関わった本が二桁突破しました。

DSC_0695

大学生の時に、当時日本XPユーザグループの代表だった長瀬嘉秀さんに声をかけていただいて翔泳社から出た本に関わって以来、約10年で10冊を突破しました。その間、本田技術研究所に就職して宇都宮に引越したり、DeNAに転職して東京に戻ってきたり、結婚したり、子会社のngmocoに転籍となってサンフランシスコに引越ししたり、とても色々ありました。ここ数カ月はちょっと忙しくて、まともにブログも書けませんでしたが、この数カ月の間にも何冊か本が出版されました。筆が遅くなりましたが、関係者の皆さんに感謝申し上げたいとおもいます。

ちなみに、このエントリーで紹介した以外の書籍は下記の通りです。

  • アート・オブ・コミュニティ ―「貢献したい気持ち」を繋げて成果を導くには
  • ポモドーロ・テクニック入門
  • 電子出版文書フォーマット技術動向調査報告書2010-2011
  • エキスパートPythonプログラミング
  • IT業界を楽しく生き抜くための「つまみぐい勉強法」
  • 実践eXtremeプログラミング
  • アジャイルソフトウェア開発スクラム
  • Xtreme Programmingテスト技法―xUnitではじめる実践XPプログラミング

100人のプロが選んだソフトウェア開発の名著

翔泳社さんの100人のプロが選んだソフトウェア開発の名著 君のために選んだ1冊企画に参加させていただきました。書いた量は全体の1/100です。紹介したのは、C++の設計と進化です。

この本は言語の歴史と、その歴史の過程の中でどのように意思決定がされて、現在の形式になっていったのかが書かれています。書いた内容が2ページなので、概略を書こうとしてしまうと、ブログにも全部書けちゃうので悩ましいのですが、「自分の道具をきちんと知ろう。正確に、詳しく、発展の過程も」といったことが訴えたかったことです。C++と銘打ってありますが、この本で書かれているような過程を、自分の好きな言語についてもなぞってみると、多くのことが学べるとおもいます。

オブジェクト指向JavaScript

技術書の翻訳で有名な水野さんと一緒に、オブジェクト指向JavaScriptの翻訳をしました。直球なタイトルどおりの内容です。原著が少し古く、ECMA Script 5ではなく3対応だったりしますが、3と5で変わるようなチャラい内容ではなく、JavaScriptの基本骨格を丁寧に紹介した本です。

JavaScript関連はブラウザ、サーバ、クライアントとさまざまな分野に広がりつつありますし、必要な知識やコードの構成は土台によってもいろいろ設計が変わってきます。最大公約数的なコアの知識を本書で得ながら、それぞれ自分が特化したい分野に関しては、ウェブサイトや技術評論社の雑誌などで最新情報をおっかける、みたいな読み方が良いと思います。HTML5だBackbone.jsだnode.jsだMeteorだ、といったキラキラした技術に触る際に、ぜひご一緒にどうぞ。「JavaScriptのDISりなら俺に任せろバリバリ〜」という発言とHTML 5で有名な、紀平さんも下記のように紹介してくれています。

Mobageを支える技術 ~ソーシャルゲームの舞台裏~

DeNAのメンバーとして、Mobageを支える技術 ~ソーシャルゲームの舞台裏~ (WEB+DB PRESS plus)の執筆に参加しました。

どちらかというと、Mobageに(生活を)支えてもらっている技術な今日この頃ですが、本書の4章のngCore関連の章を書きました。ngCore関連はこの本が出てからの数カ月でもいろいろバージョンアップし、GUIの統合開発環境のngCore Builderを使ってソースコードデバッグができるようになったり(ないしょだけど、node.jsのV8エンジンのデバッグもできるらしいですよ)、様々な統計情報がリアルタイムにグラフで見られるようになったり、エンジンも高速化されたり、動画再生が追加されたり、高速なパーティクルエンジンが入ったりと機能追加がされていたりもします。そんなどんどん良くなっていく最中のスナップショット的な感じの章になっています。

また、データベースの章なども充実な内容になっており、発売後に社内のSNSで「えー、こんなことまで書いてしまって・・・」みたいな声が上がるほどなのですごいと思います(僕は専門じゃないので他と比較とかはできないですが)。みんなで勢い良く書いた内容です。楽しんでいただければ幸いです。

posted by @shibukawa at 05:51 | Comment(89) | TrackBack(0) | 日記 はてなブックマーク - 関わった本が二桁突破しました。

2012年05月09日

Win/Mac/Linuxで圧縮テクスチャを作成する

圧縮テクスチャ。現代的なグラフィックス処理の大半はメモリ間転送ですよね。圧縮テクスチャはGPU内のメモリ使用量と転送量を削減してパフォーマンスもアップさせる魅惑のテクニックです。きっとスマートフォンのバッテリーの持ちも良くなることでしょう。

iOSはPowerVRを一貫して使っているので、PVRフォーマットが標準です。Androidの方はいちおうETC1という共通フォーマットはあるのですが、アルファチャンネルが持てなかったりするのでデバイスごとの最適なフォーマットを使うのが普通みたいです。

  • ATiTC: 元ATi(現AMD)のフォーマット。ATCとも呼ばれています。ATiのモバイル向けのプロセッサは現在Qualcommがリリースしています。よく使われていrます。アルファチャンネルの有無、アルファチャンネルの特性で3種類の内部フォーマットがあります。
  • DXTC: Direct X用共通フォーマットみたいです。nVidiaのTegra系が利用しています。これも、データの種類ごとに3〜4種類の内部フォーマットがあるらしい。
  • PVR: iOS系と同じPowerVRを載せているデバイスで使います。圧縮率、アルファチャンネルの有無で2x2の4種類あります。
  • ETC1: エリクソン社が作った標準フォーマットですが、ARM社自身が作っているMaliというGPUがこれのみをサポートしています。

そのうち、ETC2というアルファチャンネルをサポートしたフォーマットが共通で使えるようになるらしいです。このあたりは、こちらのブログを上から下まで拝むように読みまくる方が正しい情報を得られると思います。

開発ツールのみであれば、WindowsかMacだけでもいいとは思うのですが、ビルドサーバとか考えるとLinuxサポートも欲しくなるかもしれないので、その観点でマルチプラットフォームで入手可能か?で調べています。全部の検証をしたわけではないです。あくまでもメモです。

PVRフォーマット

PowerVRをリリースしている、Imagination社のサイトにツールなりなんなりが色々あります。要ユーザ登録。PVRTexToolが変換ツールです。GUIツールですが、コマンドラインからも使えるらしい。パッケージに、Windows 32/64, Linux 32/64, Mac 32の5バージョンが含まれています。Windows版だけはDXTCサポートみたい。ずるい。Apple限定でよければ、iOS用のSDKに変換ツールが付いてきます。

ライブラリとしても提供されていますので、ツールチェーンに組み込んだりもしやすいかな、と思います。ただし、ビルド手順を見ると、SDKに含まれるライブラリとかヘッダも必要とか色々書かれていて、家の遅いネットでダウンロードするのが時間がかかりそうなので詳しくおいかけてません。SDKはOpen GL ES1.1と、ES 2.0用と分かれていリリースされています。

DXTCフォーマット

今回は僕の作業では特に必要はないので詳しくは調べていませんが、nVidia社が変換ツールのソースをMIT License!で公開しています。コメントを見ると、Linuxでも動くよ、と書かれています。Macは時々落ちるかも・・・と書かれています・・・。

http://code.google.com/p/nvidia-texture-tools/

ATiTC/ETCフォーマット

なかなか調べにくかったのがこいつです。DXTCファイルから無理やり変換も見つけましたが、1ビット情報を無理やり落としてしまっていたりとちょっとデザイナーさんから怒られそうな感じ。AMDはWindows向けのツールしか提供していませんし、QualcommのAdrenoSDKもzipファイルを展開すると.exeファイルががががが。

でも、あきらめずに.exeファイルでインストールすると、変換用のライブラリが手に入ります。Windows32/64用とMac用。それにWindowsMobile、webOS、Androidもサポートしているので実機上の変換もできそうです。Linuxは残念ながら対象外。

また、Windows専用ですが、QCompressというGUI/CUIのツールも付いてきます。@nakamura001の啓示に従い、wineで動かしてみようと思います。

$ sudo port install wine
: (待つ)
$ wine ~/Downloads/AdrenoSDK/AdrenoSDK.2.3.00.exe

ふつーにWindowsっぽいダイアログが出て、インストールが行われます。初回のwine起動時は環境作ったりで時間がかかるかも。ホームの.wine以下にWindowsっぽいディレクトリ構造ができます。/users/Public/Documents/にテスト用の画像を置いてみました。

$ cd ~/.wine/drive_c/AdrenoSDK/Tools/QCompress
$ wine QCompressCmd.exe c:\\users\\Public\\Documents\\test.png c:\\users\\Public\\Documents\\test.atc "ATC RGBA Explicit"
QCompessCmd v0.01.00 (c)2011 QUALCOMM Incorporated

フォルダを見てみると、test.atcが出来ています。やったね。

上記の例で使ったQCompressがETC1にも対応しています。以上終了。

まとめ

やっぱり、Windowsの方が細かいツール類は充実していますねー。一部無理やりなところもありましたが、ひと通り欲しいデータは得られそうです。

posted by @shibukawa at 03:42 | Comment(254) | TrackBack(0) | 日記 はてなブックマーク - Win/Mac/Linuxで圧縮テクスチャを作成する

2012年04月02日

Pythonプロフェッショナルプログラミング

DSC_0937

レビューにちょびっと参加した、Pythonプロフェッショナルプログラミングが無事発売されたようです。おめでとうございます!わざわざ、アメリカにまで献本を送って頂きました。ありがとうございます。ホントにアメリカなんだぜ、というのを証明するために、USのトイザらス限定のクラシック・ソニック10インチフィギュアと、日本未発売のアニメーターズ・コレクションのポカホンタス、サン・フランシスコのローカルなアイスのThree Twinsと一緒に写真撮ってみました。

Amazonでも入荷待ちになっていますね。Amazonで買えないときは、弊社の親会社(DeNA)が運営するビッダーズで検索すると、見つかるかもしれませんよ。ポイントも付くかも?

本のタイトル的にはエキスパートPythonプログラミング とかぶっていますし、いくつか同じテーマを扱った章もあります。ですが、こちらはより実践的な、仕事で使えるような内容がより多くなっています。テーマが同じでも、より深堀してあったり(Sphinxのドキュメント)、より新しい内容を元に書かれていたり(パッケージ管理)、最近ではより広く使われているもの(Jenkins)を対象としていたり、エキスパートPythonプログラミングを持っている人でも、「おおっ」っと思える内容が多いです。まぁ、エキスパートPythonプログラミングの方は、Pythonという言語を深く深く取り扱っている本なので、当然両方そろえるべきですね【ステマ】

とくに実践的だな、と思えるのが想定環境です。最近のシステム開発だとウェブ上のシステムがかなりの割合を占めていると思いますが、仮想PCを使って、それの上で開発をすると説明されています。もしかしたら他のRailsとかの本もそうなっているのかもしれませんが(最近全然そちらは追いかけていない)、個人的には「なるほどー」と思いました。以前、大規模にPythonで開発していたときは、Windows XP上でコードを書き、Djangoで動作確認をしながら、本番環境(Windows Server 2003)にデプロイして・・・とかやっていました。細かい差であっても、結構デプロイ作業で手間暇がかかったりするんですよね。また、開発環境をシステム上に入れてしまうと、Pythonのバージョンなどで引きずられてしまったり・・・と。当時のPCは非力すぎて仮想PCは難しかったという事情もあったのですが、いろんな仕事を受託で引き受けて、ばっちり開発しているようなBeProudでは、そのあたりはしっかりとしているんだなぁ、と思いました。

かなりスキルの高い開発者を固めている印象のあるBeProudの、実践でつちかってきたノウハウがばっちり書かれた本に仕上がっています。Pythonと書かれていますが、半分ぐらいの章はPythonでなくても役に立つ話が書かれています。とても良い本です。ぜひ、みなさんお手にとって、レジまで運んでお金を払い、東京で毎月定期的に開催されているBPStudyという勉強会にも参加して、できるエンジニアの人たちのありがたいお話を聴きながら、本にサインをもらうと良いと思います。

posted by @shibukawa at 16:59 | Comment(210) | TrackBack(0) | 日記 はてなブックマーク - Pythonプロフェッショナルプログラミング

2012年03月29日

MacPortsは生まれ変わった

Golden Gate in San Francisco, California
by www.frontendeveloper.com under CC BY-SA

あ、近況報告ですが、DeNAから子会社のngmocoに転籍となり、サン・フランシスコに引越しました。また暇見つけて詳しく書きます。

MacのOSS関連のツールのインストールは昔からいろいろ歴史があります。最近の事件としては、MacPortsがほぼデファクトだったときに、Homebrewが出てきて一躍人気になり、MacPortsからの引越しネタが一時期の技術ブログでさかんに書かれたことですかね。

で、僕もいろいろ使っていました。最近は、環境を作りなおす際に時間節約と思ってHomebrewを使っていたのですが、どうしてもBoostの最新版がインストールできず(手元のフォーミュラがupdateでも更新されず、手元のフォーミュラの参照しているアーカイブはすでにsourceforge上から削除)、困ってMacPortsに戻しました。そしたらびっくり!ビルド済みのバイナリパッケージを落としてくるようになってました。

依存関係がやたら多い(X11とかも含む)py27-pilをインストールしても、7分半(fontconfigのactivateに時間かかってた)。今までのように、ビルドをしかけてから、オヤスミなさいまた明日する必要はないです。あ、僕のマシンはHDDのCore 2世代のMacBook Proです。ディスク暗号化とかいろいろかかっていてかなり重いです。Windows 95を思い出すぐらい・・・

インストールの過程を見ても、必要なパッケージはだいたい自分のサイトのところに置いていて、サードパーティのサイトのリンク切れとかに悩まされられない安心感もいいですね。ビルドしないからSSDみたいな環境の人にいいと思います。スペースが余計に使われないので。また、ビルドしないので、HDDみたいな環境の人にいいと思います。ビルドの時間がかかりませんし。なにより、CPUパワーと時間が食われて熱となって消えていくわけですから、バイナリを使ったほうがエコですよね。gentoo好きみたいなビルド好き以外の人はMacPortsを選んでおけば間違いないと思います。作業のインフラとしては。

まぁ、比較してみると、ちょっとパッケージに収録されているバージョンが古かったり(node.jsは0.6.10。Homebrewは0.6.14)、というのはありますが、gitとか、安定している仕事のツールを揃えるにはいいんじゃないでしょうか?

今、Boostを+universalでインストールしていますが、基本バイナリで、見つからないやつだけソースコードからビルドしている模様。icuのuniversalバイナリはなかったか・・・でも、icuのソースはmacports.orgから取ってきていました。Boostのソースはsourceforgeでしたけど。

Homebrewさん、お世話になりました。

posted by @shibukawa at 05:54 | Comment(185) | TrackBack(0) | 日記 はてなブックマーク - MacPortsは生まれ変わった
検索ボックス

Twitter

www.flickr.com
This is a Flickr badge showing public photos and videos from shibukawa.yoshiki. Make your own badge here.
<< 2017年12月 >>
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
最近の記事
カテゴリ
過去ログ
Powered by さくらのブログ