Qtブログ(日本語)

Mac でのエイリアンウィジェット

作成者: 朝木卓見|Feb 24, 2011 1:17:17 PM

この記事は Qt Blog の "Alien widgets on Mac" を翻訳したものです。
執筆: Richard Moe Gustavsen 2011年2月23日

今のところ、Qt for Mac OS X では全てのウィジェット([qt QWidget])が NSView クラスのインスタンスを作成しています。これはすなわち、アプリケーションが持つウィジェットの親子関係を反映した Cocoa フレームワークにおける表示の親子関係を、Qt が保持しているという事です。各 NSView は OS のネイティブのイベントを受け取り、対応するウィジェットに転送します。イベントを受けて Qt がそれ自身の方法でマウスのグラブやウィンドウのポップアップなどをするためには、各ウィジェットで追加の処理と書き換えをして [qt QEvent] に変換したうえで、プラットフォームとは独立した手段でアプリケーションに送り出します。

Apple は NSView を使いすぎないように慎重に利用する事を推奨しています。最適化のためには、その数が 100 未満になるように努めるべきでしょう。しかし、作成した Qt アプリケーションがウィジェットを大量に使用している場合には、簡単にこの制限を超えてしまいます。その結果、下記の最初のムービーのようにアプリケーションが重たくなってしまいます。このサンプルアプリケーションでは、無謀にも 2000 ものウィジェットを作成しています。ここで作成したウィジェットはマウスの移動に従ってハイライトするボタンです。ご覧になったとおり、アプリケーションの規模の増大に対応できず、大きな遅延が生じています。

UI を素晴らしくするために大量のウィジェットを使用する傾向のあるユーザーにとっては、この制限は致命的になりかねませんでした。幸いな事に、この問題に対して Qt には「エイリアンウィジェット」と呼ばれる解決策があります。Qt 4.4 からは Qt for Windows や X11 でエイリアンウィジェットはデフォルトで使用されており、基本的には各ウィジェットがネイティブのウィンドウハンドルを所持する必要性を取り除いています。Mac においては、これは Qt の各ウィジェットが NSView を使わない場合があることを意味します。その代わり、出来る限り Cocoa を迂回するために、ウィンドウを保持する NSView をただ一つ作成して、その NSView を Qt 自身がウィジェットに分割して利用しようとします。

これには三つの側面があります。一つはイベントがアプリケーションに届く前に実行する必要があるコードの量が減らせる事です。たとえば、マウスが押されたときに Cocoa が正しい NSView を見つけて、次に Qt がイベントを(マウスのグラブやポップアップメニューなどのために)他のウィジェットへ転送するよりもむしろ、マウスのイベントを Qt が直接扱う方が単純です。次に、イベントのハンドリングがプラットフォーム固有のコードから、プラットフォームとは独立したコードへ移行していく事です。これによって、時がたつにつれて Qt for Mac とその他の Qt との間に生じかねない違いを減らせる事が期待できます。そして最後に、Apple の推奨に従って NSView の利用数が減らせる事です。NSView を数多く利用する事でアプリケーションが遅くなるのは確かです。二つ目のムービーは最初のムービーと同じサンプルをエイリアンウィジェットを使って動かしたものです。遅延は全く見られません。

エイリアンウィジェットは Qt for Mac(Cocoa) 4.8 からデフォルトで使用されます。

(もちろん、ソースコードを入手して Mac でのエイリアンウィジェットを試していただく事も出来ます)