syghの新フラグメント置き場

プログラミングTipsやコード断片の保管場所です。お絵描きもときどき載せます。

CScrollViewの代わりにCViewでスクロール

(これは2010-09-07に書いた故OCNブログの記事を移植したものです)

MFCのCScrollViewは便利なんですが、画像編集ソフトのようなものを作ろうとしたとき、いかんせん細かい制御がしづらいというか、CScrollView::SetScrollSizes()などのユーティリティ メンバー関数を呼び出すタイミングが微妙というか、デバイス座標系と論理座標系が入り乱れて混乱するというか、とにかくスクロールは自前でやったほうがかえって楽だったりします。実はそんなに手間じゃありません。

サンプル:
MfcScrlVwTest.zip
(VS 2010 SP1でビルド、Windows XPと7で動作確認済み)

(left, top, right, bottom) = (-4,000, +4,000, +4,000, -4,000)の論理座標空間を、クライアント領域にマッピングしています。また、Y軸はいわゆる下が正となる2D座標系ではなく、座標変換を使って上が正となるように設定しています。ビューポートをいろいろ設定するだけで、拡大縮小・平行移動とスクロール バーの連動が簡単に実装できるんですが、GDIのビューポートは、OpenGLDirect3Dのそれとは毛色がちょっと違うので最初戸惑いました。まぁいまさらGDIっていうのも時代錯誤な感じですが……

で、サンプルのソースはほとんどMfcScrlVwTestView.h/cppしかいじってません。あとはフレームワークが自動生成したコードをビルドするだけで、わりと見栄えのいいアプリになるのはMFC Feature Packの良いところです。実装したのはスクロールの確認と簡単なダブル バッファリングだけで、完全な印刷処理は実装してないので、そのへんはご自由にどうぞ。

なお、ダブル バッファリングにおけるバック バッファ→フロント バッファの転送処理は、転送元と転送先ともにデバイス座標系に戻して行なったほうが分かりやすいです。

Direct2D

CViewでスクロール バーを扱うコツがつかめたら、グラフィックスのレンダリングには可能な限りGDIではなくDirect2Dを使うようにしましょう。Direct2Dは明示的なバック バッファの作成が不要で、EndDraw(もしくはDXGIスワップチェーンをPresentするタイミング)でフリップしてくれます。ちなみにDirect2DはGDIのデバイス コンテキストにもレンダリングできるようになっていますが、GDI/GDI+とは違って、Direct2Dでは直接印刷(プリンターのデバイス コンテキストに描画)できません。ID2D1RenderTarget::EndDraw()メソッドがエラーコードを返します。なので、印刷時のみGDI+で同じ描画処理を実行するようにするか、ビットマップに一旦描画してプリンターに転送する必要があります。ただし、Windows 8で追加されたDirect2D 1.1であれば印刷用のメタデータ出力もサポートしています。