Mesoscopic Programming

タコさんプログラミング専門

Programming Tips #10 ツリービューの謎が解けた

スクロールバーの位置を変更したら WM_SIZE を送れ!

ツリービューの選択アイテムを上下キーで変更すると、垂直スクロールバーは選択アイテムが表示されるように自動で調整されるけど、水平スクロールバーはそうならないよね。
なんでやねん、と怒りつつも自分で何とかするしかないので死ぬほど調査した。
そして解決方法をやっと見つけました。
スクロールバーの設定は前回の復元方法と同じなんだけど、実は前回のはたまたまうまく行ってただけなんだよね。
初期化の直後はちゃんとスクロールバーの設定どおりに表示されるのに、それ以外ではスクロールバーのつまみだけ更新されて中身は変化なし。
何でだろ、何でだろ、って試行錯誤してたら犯人は WM_SIZE メッセージだったのだ。
初期化の直後は表示の開始なので自動的に WM_SIZE が送られていたのだ。

選択アイテム変更通知イベント

LRESULT App :: OnTvnSelChanged()
{
    RECT rcItem;
    RECT rcClient;
    LONG xpos;

    TreeView_GetItemRect( hTreeView, lpnmtv->itemNew.hItem, & rcItem, TRUE );

    rcItem.left -= GetSystemMetrics( SM_CXSMICON );

    GetClientRect( hTreeView, & rcClient );

    if ( ( rcItem.left < rcClient.left && rcItem.right < rcClient.right )
      || ( rcItem.left > rcClient.left && rcItem.right > rcClient.right ) )
    {
        xpos = GetScrollPos( hTreeView, SB_HORZ ) + rcItem.left;

        SetScrollPos( hTreeView, SB_HORZ, xpos, TRUE );

        SendMessage( hTreeView, WM_SIZE, 0, 0 );
    }
}
解説

選択されたアイテムの表示矩形を取得し、ツリービューのクライアント領域と比較し、はみ出てるようなら中に入れてあげる。
最後に WM_SIZE メッセージを忘れずに送る。これで万事OK。

以上。