スクロールバーの使い方

スクロールバーの使い方を説明します。始めはスクロールバーの使い方をヘルプの使い方の例として使おうかと思ったのですが、あまりに難しいので、止めました。

スクロールバーっていうのはプログラマに嫌われているコントロールベスト3に入るようですねー。でもMAPエディタでは微妙に位置を決める必要がありそうなのであえてこれを使います。使ってみるとそれほど難しくはありません。ただヘルプだけ見て使うのが難しいということです。

難しい理由のひとつが、スクロールバーを使うのにメッセージハンドラを使う必要があるということです。つまり、タイマーや、キー入力と同じ手続きが必要なんですね。普通のコントロールはメンバ関数でことが足りるのでそう思って調べると使い方がわからなくなってしまうという・・・何という仕様でしょうか。おまけにスクロールバーがいくつあっても呼ばれるメッセージハンドラは同じ場所というのが余計に難しくしています。

私の想像では、ウィンドウ自体が使うスクロールバーをコントロール化したので少々無理があるのではなかろうか、と思います。

では実際に使ってみます。

フォームの上にスクロールバーの横と立てをそれぞれ2個つづ配置します。

まず、ここまででビルドして動かしてみましょう。

どうなりましたか?  動かない?  そうですね、これがふざけたことに動かないんです。スクロールバーを移動してもゴムみたいにパッチンと元に戻ってしまいます。実は動いたらプログラマがちゃんとその位置をセットし直さないと動かした位置に止まらないのです。とても変なコントロールだと思いますね。

では止まるようにします。

クラスウィザードを起動して、スクロールバーのメンバ変数を決めます。
ここでは、m_Scrol1,m_Scrol2,m_Scrol3,m_Scrol4 の4個にしました。
それぞれのスクロールバーにはこの変数を使ってアクセスします。

スクロールのハンドラを作るにはタイマのハンドルを作るときと同じようにまず、クラスウィザードを起動します。VIEWを選択して、メッセージのWM_HSCROLを選択します。クリックして下のON_WM_HSCROLをダブルクリックします。するとハンドラが出来ます。ここがスクロールバーを動かしたときに呼ばれるハンドラです。

スクロールバーの働き方は、タイマや、キーボードや、マウスボタンと同じようなメッセージの回りかたをするので使うのもマウスボタンなどと同じ手続きが必要になるわけです。

ハンドルを作ったらそこに以下のコードを打ち込んでみましょう。
 

void CScrollbar1129View::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
 
m_Scrol1.SetScrollRange(0,100,TRUE);---------------------------------A
m_Scrol2.SetScrollRange(0,100,TRUE);
 
int x, xmin, xmax;
 
x=pScrollBar->GetScrollPos();----------------------------------------B
pScrollBar->GetScrollRange(&xmin, &xmax);
switch(nSBCode)
{
case SB_LEFT : x=xmin; // 左端へスクロール--------------------C
 break;
case SB_LINERIGHT : x++; // 右へ1単位スクロール
 break;
case SB_LINELEFT : x--; // 左へ1単位スクロール
 break;
case SB_PAGELEFT : x-=10; // 左へ1ページスクロール
 break;
case SB_PAGERIGHT : x+=10; // 右へ1ページスクロール
 break;
case SB_RIGHT : x=xmax; // 左端へスクロール
 break;
case SB_THUMBPOSITION: x=nPos; // 左端へスクロール
 break;
}
 
if (x<xmin) x=xmin;--------------------------------------------------D
else
if(x>xmax) x=xmax;
 
pScrollBar->SetScrollPos(x);-----------------------------------------E
 
if(pScrollBar == &m_Scrol1)-----------------------------------------F
{
 // ScrollBar1 の処理
}
 
if(pScrollBar == &m_Scrol2)
{
 // ScrollBar1 の処理
}
if(pScrollBar == &m_Scrol3)
{
 // ScrollBar1 の処理
}
 
CFormView::OnVScroll(nSBCode, nPos, pScrollBar);
}
 

A---スクロールバーの範囲を指定します。これは一度だけ指定すれば良いはずなので 「OnCreate」 とか 「PreCreateWindow] とかでかけばよいと思うのですが、そうするとアサートされます。
で、ばかばかしいとは思いつつ、ここに書きます。よこすクロールが2本あればそれぞれに2個必要です。まあ時間的にはそれほどロスがあるわけではないので我慢しましょう。より合理的な場所がわかったら教えてください。

B---スクロールバーの変化した位置を取得します。ここにはpScrollBarという、スクロールバーへのポインタが渡されてくるので、そのポインタを使うと使用したスクロールバーの位置を取得することができます。

C---「nSBCode」 にはスクロールバーのどこを動かしたか、というのが入ってくるのでそれに応じて位置を変化させなければなりません。世話のかかる・・・

D---X位置を動かしてみて外に飛び出ていないか確認してから、

E---その位置につまみをセットする・・・と、やっとつまみが動くようになります。

F---2個あるうちのどのスクロールバーを動かしたのか調べるためにはこのように、ポインタを比較します。一致したものが、動かしたスクロールバーなので、それ用の処理をします。
実際には、Cの処理もそれぞれのスクロールバーにあわせないといけないような気がしますね。

縦のスクロールバーにもこれと同じように記述します。