ちょっと複雑なダイアログを表示する必要があって、Pocket PCの画面には入りきらない。Pocket PC Developer Networkにスクロールするダイアログのサンプルがあったよな…と思い覗いてみる。ありました。
QA: How do I scroll the contents of a dialog?
しかし、このサンプルを動かしてみると問題発見。画面の縦横切り替えはPocket PC 2003 SEからついた機能なのか、これで、縦画面でダイアログを表示した後、横画面に切り替えると、システムが縦画面の高さ分を表示するためのスクロールバーを出してくれる(表示しきれないコントロールがある場合のみ)。このシステムの用意するスクロールバーと干渉するのである。ご覧の通り:

あはははは。これじゃ使えません。しょうがないな、といってここ数日かけて自作のスクロール・ダイアログ・クラスを作りましたよ。ATL::CDialogImpl継承して。ああ、苦労したけど、やっと完成した。
と思った途端に、WTLにはatlscrl.hで数々のスクロール・ウィンドウをサポートしていることを知った。あああ。あの苦労は何だったの。がっかりしちゃいました。WTLって悪くないんだけど、ドキュメントが無いんでせっかくの機能が見つけられない。困ったものです。
もっともWTLのatlscrl.hにはダイアログを直接サポートするクラスは無い。いろいろ読み込んだ結果、CScrollWindowImplクラスをそっくりコピーして、ATL::CWindowImplの代わりにATL::CDialogImplを継承する、CScrollDialogImplクラスを作成してみたところ、あっさり動きました。デスクトップでもPocket PCでも。
template <class T, class TBase = CWindow>
class ATL_NO_VTABLE CScrollDialogImpl : public ATL::CDialogImpl<T, TBase>, public WTL::CScrollImpl<T>
{
...中身はCScrollWindowImplからコピー(30行ほど)
}
これでCDialogImplの代わりに使えます。CScrollImplの使い方サンプルは以下が良いかな。
ATL/WTLによるWindowsプログラミング:スクロール
動かしてみると、スクロール動作がぎこちないね。私の自作ダイアログはDeferWindowPos使ったんできれいだったぞ(追記:私のコードはビットマップスクロールをしてないのでスムーズだったのかも)。それと、このままではフォーカスの当たるコントロールに自動スクロールする機能が無いので、それだけ追加しなきゃ(ScrollToView()関数があるので楽そう 追記:使い物にならなかった。脚注参照)。も一つ、ダイアログ内にスクロールバーコントロールがあると、そのメッセージを自分のコードで遮断しないと、ダイアログのスクロールバーが動いちゃいます。俺のコードはその辺の面倒ぐらい見たぞ。
下のスクロールバーを出すために書いたコードは基本的に3行だけです。OnInitDialog()で、
SetScrollSize(content_size_x, content_size_y);
SetScrollLine(10, 10);
SetScrollPage(100, 100);
追記:上の三行の前にCScrollImpl::GetSystemSettings()もしくはSCrollImpl::OnCreate()を呼び出しておくべきですね。


しかし、Pocket PCのウィンドウを全画面表示しているのに、ウィンドウのスクロールバーが最外側1ドットにボーダーを表示するのが気にいらねえ(笑)。
※CScrollImpl::ScrollToView()は使い物にならん。RECTを渡してやるとRECTを表示する範囲内でできるだけ原点に近いほうにスクロールする。だから画面の真中に表示されているコントロールをクリックすると右下に逃げたりする。このコードどういう目的で設計したんだ?追記:よく分からん。調べなおします。追記の追記:調べました。バグでしょう。