CScrollViewのスクロールバー表示について質問があります。
表示内容のサイズがクライアント領域の最大サイズに満たないとき、
通常だと、スクロールバーは表示されませんが、
表示内容のサイズにかかわらず、常にスクロールバーを表示させて
おきたいのですが、方法がわかりません。
MSDN等で、ウィンドウのスタイルを調べてみたのですが、
該当しそうなものが見つかりません。
リストボックスの場合、スタイルに LBS_DISABLENOSCROLL を指定すれば
スクロールするほど内容がなくても、スクロールバーが使用禁止状態で
表示されるのですが...
SetScrollInfo()で、
SCROLLINFO構造体のfMaskにSIF_DISABLENOSCROLLを指定すると
できるかもしれません(未確認です)。
CScrollViewから、独自のクラスを派生させて、そこから
CWnd::SetScrollInfo()や、CWnd::SetScrollRange()をコール
してみたのですが、うまくいきません。
コールしたタイミングは、CScrollView::SetScrollSizes() で、
ビューのクライアントサイズを設定した直後です。
CScrollView::SetScrollSizes() をデバッカで追ってみたところ、
その中で、CScrollView::UpdateBars() という関数コールを見つけました。
この関数は、クライアントサイズが更新された後に、スクロールバーの
表示を制御しているもののようです。
そして、そこでは、CWnd::SetScrollInfo()や、CWnd::SetScrollRange()
を使っていたので、上記関数を使用すること自体は、間違ってないようです。
コールするタイミング等を変えていろいろ試しみようとおもいます。
スクロールバー制御の詳しい方がいましたら、ぜひアドバイスをお願いします。
>スクロールバー制御の詳しい方がいましたら
全然詳しくないですけど
そんなに使えないんだったら、自前でスクロールバーを準備しては?
> そんなに使えないんだったら
CScrollView が「使い物にならないViewならば」 の意味です。(^^;
> その中で、CScrollView::UpdateBars() という関数コールを見つけました。
この中で、バーが不要なときは非表示にしてますね。
なので、SetScrollInfoなどを呼ぶ前にEnableScrollBarCtrlなどで
表示してやる必要があると思います。
> SetScrollInfoなどを呼ぶ前にEnableScrollBarCtrlなどで
> 表示してやる必要があると思います。
実は、CScrollView::UpdateBars() のバーを表示する処理を
ほぼそのままコピーしてやってみたりもしたのですが、
うまくいきませんでした。
> そんなに使えないんだったら、自前でスクロールバーを準備しては?
実は、それも考えてみたのですが、あまりにも手間がかかりそうなので、
当掲示板で、簡単な方法はないものかと質問してみたわけです。
スクロールバーを表示したままで、何がしたいかというと、
表示内容を、ビュー幅に合わせたり、ビュー高さに合わせたり
させたいのです。
そして、そのためには、表示内容と現在のビューサイズをもとに
拡大縮小率を計算しなければならないのですが、
スクロールバーが表示されていたり、されていなかったりすると
ビューサイズが変わってしまい、計算処理がかなり複雑になってしまいます。
そこで、スクロールバーを表示したままにして、ビューサイズを
一定にさせたいと思ったわけです。
スクロールバーを表示させるだけでいいのなら、
void CSCRView::OnInitialUpdate()
{
SetScrollSizes(MM_TEXT, 画面より大きなサイズ);
}
void CSCRView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
SetScrollSizes(MM_TEXT, 画面より大きなサイズ);
}
ではいかがでしょうか?
K さんのいわれるように、
表示内容を、スクロール最大範囲 + 1 にして、
バーを表示させるようにもしてみましたが、
そうすると、スクロール幅が多少ずれてしまい、見栄えが悪く
なってしまいます。
+1 しかしていないのに、もっとスクロール幅があるように
表示されます。たぶん、スクロールバー自体の幅がスクロール幅に
加算されているようです。
かといって、あらかじめ、バーの幅を計算してしまうと、
最大範囲を超えなくなってしまい、バーが表示されません。
どうせ見た目だけの問題なので、無理に表示するのは
やめようと思います。
冒頭でも書きましたが、リストボックスの場合、スタイルの
設定だけで同じようなことが実現できてしまうので、
スクロールビューでも同じようなことができないかと思い、
質問してみました。
でも、スクロールビューの場合は、簡単にはできないみたいですね。
回答してくれて、ありがとうございました。
こんにちはべーちゃんです。VC++は最近始めたばかりなので
ちょっとはずしているかもしれませんが、MSDNをみたところ
>スクロール バーは次に示すように、ビューの適当な 3 箇所に表示されます。
>-標準ウィンドウ スタイルのスクロール バーは WS_HSCROLL と WS_VSCROLL
> スタイルを使ってビューに設定できます。
>-ビューを含むフレームにスクロール バー コントロールを付加することも
> できます。このとき、フレームワークは、フレーム ウィンドウから現在
> アクティブなビューに WM_HSCROLL と WM_VSCROLL メッセージを転送します。
>-フレームワークは、CSplitterWnd 分割コントロールから、現在アクティブな
> 分割ペイン (これはビューです) にスクロール メッセージを転送できます。
> CSplitterWnd に共有スクロール バーが置かれているときは、CScrollView
> オブジェクトは、独自にスクロール バーを作成せずに共有スクロール バーを
> 使います。
とあり、このうち2番目の方法、つまりビューを含むフレームに
スクロールバーコントロールをつけるというのはどうでしょう?
一応常時つくことは確認しました。但し、ステータスバーとツールバーの
表示位置がスクロールバーの内側だったのでその辺の調整がうまくいくかは
わかりませんが
>実は、CScrollView::UpdateBars() のバーを表示する処理を
>ほぼそのままコピーしてやってみたりもしたのですが、
>うまくいきませんでした。
そんなことは無いと思います。あとでどんな影響があるか心配ですが。
>どうせ見た目だけの問題なので、無理に表示するのは...
見た目、というのは、スクロールバーの中の四角いボックスのことでしたら
EnableScrollBarCtrl(SB_VERT, needSb.cy);
if (needSb.cy)
{
info.nPage = sizeClient.cy;
info.nMax = m_totalDev.cy-1;
info.nMax = 0;
//info.nMin, info.nMax ともに0で
//ボックスの大きさがバー全体にひろがりました。
//ドキュメントのクライアントサイズより小さいときは、利用できそうです。
if (!SetScrollInfo(SB_VERT, &info, TRUE))
SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
}
追伸です。
標準で備わったものをむりにかえるようなコードはよくないですよね。
ベーちゃん(ちゃんがあるので敬称を略しました)の方法がいいですね。
みなさん、ありがとうございます。
見た目の問題なので、表示内容がビューフレームの最大サイズに満たないとき
(デフォルトだとスクロールバーが非表示)は、アプリケーション側で、
デフォルトと同じようにスクロールバーを表示すれば、今回の件は解決しそうです。
また質問すると思いますが、そのときはお願いします。