読者です 読者をやめる 読者になる 読者になる

B(ug)log

開発とかぼやきとかLINEスタンプとか http://line.me/S/sticker/1245783 職探し中

空間ナビゲーション実装(その 4)

続きです。

Windows 上で空間ナビゲーションを実現したい - B(ug)log
空間ナビゲーション実装(その 2) - B(ug)log
空間ナビゲーション実装(その 3) - B(ug)log

昨日の課題:移動先を決定する際、全要素を取得している処理が高コストでレスポンスが悪い。

というわけで今日は、上記の課題をどーにかします。ボトムアップ方式、トップダウン方式のどちらかで高速化できないか検討していきます。

ボトムアップ方式

フォーカスがあたっている要素から親の要素を辿っていく形式で移動先を決定する方式

結論:これは駄目

どの親まで遡ればいいのか?という点が問題になります。何回親を辿れば十分なのでしょうか。下図の例で、checkBox1 にフォーカスがあたっていて、右方向へ移動する場合を考えてみます。checkBox1 → groupBox1 → MainWindow と親を 2 回辿ることで、右方向にある groupBox3 を取得できるようになります。逆に checkBox2 にフォーカスがあたっていて、左方向へ移動する場合は、checkBox2 → groupBox2 → groupBox3 → MainWindow と 3 回親要素を辿らないといけないです。

f:id:u338steven:20160503205550p:plain

実際のところ MainWindow まで親を辿らないと確実ではないです。結局、処理回数的にはトップダウン方式と変わらなくなります。またトップダウン方式とボトムアップ方式でどちらが速いのか少し計測してみたところ Window Automation API ではトップダウン方式の方が処理が速いようです。よって、この考え方は不採用としました。

やっぱトップダウンですよ

こっちを工夫することにします。やり方は、フォーカスのあたっている要素が所属するグループ内の要素と、移動先の方向にあるグループの中の要素のみ走査対象にします。下図を例にすると、フォーカスのあたっている checkBox2 から下方向に移動しようとした場合、青く塗られたグループの中の要素(例えば listBox1 の item1 とか) は走査しません。なのでその分だけ速くなるわけです。

f:id:u338steven:20160503205608p:plain

至極、真っ当な手段です。何故最初からやらなかった。いや、ちゃんと言い訳があるです。それは(以下略)。

結果として

昨日は 20-300ms かかっていたのが、20-180ms にまで落ちつきました。foobar2000 で昨日は 2 秒かかっていたところが 300-600ms くらいまでになってます。

もう無駄に要素の位置情報を取得している箇所は無いはずなので、これ以上劇的な処理時間の削減はできないと思います。(要素の位置情報を取得する処理が一番重くて、 処理時間の 8 割以上がこいつなので、できるだけこの処理をしないように今回対処したのです。他の処理はかかっても数十 ms です)

残りの課題

今日判明した Tab、Pane 問題。Windows Automation API 特有の問題(というか Windows 自体の問題というかなんというか……)です。

  • 特定の Pane コントロールにフォーカス移動すると、キー入力、マウス入力がほぼできなくなります。Explorer (ファイラー)がそうなるっておかしいよ……。
  • WPF と、それ以前のフレームワーク(Win32API, WinForms)では TabItem コントロールの子要素の持ち方が異なるため、WPF ではフォーカスの移動先を決定できない場合があります。

なんだか今日はすごく眠たいので、詳細はまた後日……。やっと終わりが見えてきたかも。