2023/04/10

スクロールバー動的設定時の注意点




スクロールバーは、シート上でもユーザーフォーム上でも良く使われるコントロールです。その設定も「最大(Maxプロパティ)」「最小(Minプロパティ)」だけで無く、「シャフトの増分(LargeChangeプロパティ)」「スクロール矢印の増分(SmallChangeプロパティ)」の設定により操作性が変わってきます。
またデータ量に合わせて、動的にスクロールバーの設定値を変化させる場合もあると思います。しかし、設定値の組合せによっては「スクロールボックスが消える」「スクロールバーが操作できない」状態になることがあります。

今回は、スクロールバー(主にActiveXコントロール)のプロパティの内、「Max」「Min」「LargeChange」「SmallChange」の4つのプロパティの関係について、簡単なツールも使いながら説明をします。

1.スクロールバーの設定をするツールの概要

今回説明のために、スクロールバーの設定値を簡単に変更できるツール(サンプルファイル)を用意しました。これを使って、以下で説明をしていきます。図01がツールの内容です。
スクロールバー用ツール概要
図01


今回、状態や動作を確認するのは図01の一番右側の大きなスクロールバーです。その設定値を中央部の4つの設定用スクロールバーで変更させます。
設定用スクロールバーは、上から「Max」「Min」「LargeChange」「SmallChange」を変更させます。

また設定用スクロールバーの初期化をするのが、図01の一番左側のStartボタンです。
初期化すると各設定用スクロールバーの範囲を「-50 ~ +50」にし、また値をゼロにします。ですので、Startボタンにより、一番右の確認用スクロールバーは「Max = 0」「Min = 0」「LargeChange = 0」「SmallChange = 0」となります。

2.スクロールバーの概要

まず、スクロールバーの各部の名称は図02のように呼ばれています。

スクロールバーの部位名
図02


スクロールバーの操作には3つの方法があります。1つ目は「スクロールボックス」をマウスでつかんで動かす方法、2つ目は「スクロール矢印」をクリックする方法、3つ目がシャフト部をクリックする方法です。

操作する場所によって、変化する値は以下のようになります。
 「スクロールボックス」:値は1ずつ変化します。
 「スクロール矢印」  :値は「SmallChangeの値」ずつ変化します。
 「シャフト部」    :値は「LargeChangeの値」ずつ変化します。
そして、スクロールバーの左端が「Min値」、右端が「Max値」となります。縦方向に配置した時には、上端が「Min値」、下端が「Max値」です。

なお各プロパティには、Long型(-2,147,483,648 ~ +2,147,483,647)の整数値を指定します。

3.スクロールバーの各プロパティ値の間の関係

ツール(サンプルファイル)で「Startボタン」をクリックしてみると、スクロールバーは図03のような状態になります。
設定値が全てゼロの状態
図03


図03は「設定値が全てゼロ」となり、確認用スクロールバーは「スクロールボックスが表示されない」状態になります。
一般のユーザーならパニックになるでしょうし、「Excelが壊れた」と思うかもしれません。
「MinもMaxもゼロ。値を動かしようが無いから、スクロールボックスが現れる訳が無い」と気が付かれた方もいるかもしれません。では、図04のような状態はどうでしょう。
設定値がゼロでは無いが、スクロールボックスが現れない状態
図04


「動かせる範囲があるのに、スクロールボックスが現れない」という条件もあるのです。

3ー1.Max値とMin値

スクロールボックスが現れる必要条件は、図05のように「Max値とMin値に差」があることです。
通常は「Max値 > Min値」のように設定すると思いますが、逆にして「Max値 < Min値」としてもOKです。
MinとMaxと値に差をつけるとスクロールボックスが現れる
図05


3ー2.LargeChange値

「Max値とMin値に差」を与えても、LargeChange値によりスクロールボックスが現れるか否かが変わります。
図06のように「Max値とMin値の差 < LargeChange値」になると、スクロールボックスが現れません。「Max値とMin値の差 ≥ LargeChange値」で現れるようになり、イコールの時でもOKです。
MinとMaxとの差よりもLargeChange値を大きくするとスクロールボックスが現れない
図06


また、LargeChange値をマイナス値にすると、Max値・Min値にかかわらず図07のようにスクロールボックスは現れません。
LargeChange値をマイナスにするとスクロールボックスが消える
図07


以上を整理してグラフで表すと図08になります。「青色+緑色」の範囲がスクロールボックスが現れる条件です。
MinとMaxの差とLargeChange値の関係グラフ
図08


但し、緑色の範囲(Max値とMin値に差 且つ LargeChange値=ゼロ)の場合は、LargeChangeの変更場所であるシャフト部をクリックしても(LargeChangeがゼロなので)Value値は変化しません。なお緑色の範囲でも、スクロールボックスをマウスで動かすと値は変化しますし、SmallChangeがゼロ以外であればスクロール矢印でも値は変化します。

3ー3.SmallChange値

SmallChange値は、スクロールボックスが現れる・現れないに対しては無関係です。
しかし、図09のようにSmallChange値がゼロの場合は、スクロール矢印をクリックしても値は変化しません。但しスクロールボックスでの移動やシャフト部での操作では、値を動かす事が出来ます。
SmallChangeがゼロだとスクロール矢印では動かない
図09


なおSmallChange値がゼロの時にスクロール矢印をクリックすると、スクロールボックスは反応し点滅するので「指令は行くのに、値がゼロだから動かない」という状況のようです。

また、SmallChangeにマイナス値を設定することは可能です。但し図10のように「スクロール矢印をクリックすると、スクロールボックスが逃げていく」という現象になります。
SmallChangeがマイナスだと逆に動く
図10


このSmallChangeがマイナス時の「スクロールボックスが逃げていく」現象は、図11のようにMax値とMin値を逆転させた時でも同じです。つまりSmallChangeがマイナスだと「操作感に違和感」が出るので、マイナス値を使う場面は少ないと思います。
SmallChangeがマイナスだと、MaxとMinを入れ替えても逆に動く
図11


以上のSmallChange値の関係を整理すると図12のようになります。緑色の範囲(Max値とMin値に差 且つ SmallChange値=ゼロ)の場合は、スクロール矢印での操作は不可となります。
MinとMaxの差とSmallChange値の関係グラフ
図12


4.ツールの説明

4ー1.ワークシート(今回はSheet1)

今回使用するツールは、シート上に図13のようにコントロール類を配置しています。
シート上にコントロール類を配置
図13


スクロールバーに設定するプロパティは、今回「Max」「Min」「LargeChange」「SmallChange」の4種ですので、4つの設定用スクロールバーを並べて配置します。各スクロールバーの設定値は、E列の黄色セルに表示されます。
設定される側の確認用スクロールバーは、シートの右側に配置します。そのスクロールバーの値(Value値)は、H4セル(黄色セル)に表示されるようにしています。

設定値を初期化(4つのスクロールバーのMax・Min値の設定、および値をゼロにする)する「Startボタン」をシートの左側に配置します。そのボタンには、シートモジュールの「SBiniプロシージャ(図14)」をマクロ登録します。ボタン上の文字列は、配置時に手動設定しています。
スクロールバーの説明書きはセル上に書き込んでいます。

4ー2.シートモジュール(今回はSheet1)

4ー2ー1.設定スクロールバーの初期化

「設定スクロールバー初期化」の為のStartボタンをクリックした時に呼び出されるのが図14です。
  1. '========== ⇩(1) 初期化 ============
  2. Sub SBini()
  3.  Dim SBs(1 To 4) As Variant   '←設定用スクロールバーの配列
  4.  Dim SB As Variant     '←1つ1つのスクロールバー
  5.  Set SBs(1) = Me.ScrollBar1
  6.  Set SBs(2) = Me.ScrollBar2
  7.  Set SBs(3) = Me.ScrollBar3
  8.  Set SBs(4) = Me.ScrollBar4
  9.  For Each SB In SBs
  10.   SB.Max = 50
  11.   SB.Min = -50
  12.   SB.Value = 0
  13.  Next SB
  14. End Sub
図14


今回は同じような設定用スクロールバーが4つあり、またその設定内容が一緒ですので、4つをセット(言わば、スクロールバーのコレクション)にして設定処理をします。但しShapesのようなものが存在しないので、配列の形にします。
02行目「Dim SBs(1 To 4) As Variant」では4要素の配列を宣言し、03行目「Dim SB As Variant」では1つ1つのスクロールバーの変数を宣言します。
05行目「Set SBs(1) = Me.ScrollBar1」で、Max値を設定するスクロールバー(ScrollBar1)を配列の1番目に格納しています。オブジェクトとして格納する必要があるのでSetステートメントを使用します。
他のスクロールバー(Min用のScrollBar2、LargeChange用のScrollBar3、SmallChange用のScrollBar4)も同様に、06~08行目で配列に格納していきます。

10行目「For Each SB In SBs」では、スクロールバーのオブジェクトを格納した配列SBsから1つずつスクロールバーを取り出します。
11行目「SB.Max = 50」では、設定用スクロールバーの最大値を50に設定しています。
12行目「SB.Min = -50」では、最小値を-50に設定しています。
13行目「SB.Value = 0」では、初期の値をゼロに設定しています。
なお、今回の設定範囲は「-50 ~ 50」としましたが、Long型の範囲であれば問題ありません。

4ー2ー2.設定処理

設定用スクロールバーを操作した時には、図15のようにそれぞれのスクロールバーのChangeイベントが発生します。そしてその中で、確認用スクロールバーの設定をしていきます。
  1. '========== ⇩(2) Max値設定用スクロールバー ============
  2. Private Sub ScrollBar1_Change()
  3.  Me.ScrollBar5.Max = Me.ScrollBar1.Value
  4.  Me.Range("E1") = Me.ScrollBar1.Value
  5. End Sub
  6. '========== ⇩(3) Min値設定用スクロールバー ============
  7. Private Sub ScrollBar2_Change()
  8.  Me.ScrollBar5.Min = Me.ScrollBar2.Value
  9.  Me.Range("E2") = Me.ScrollBar2.Value
  10. End Sub
  11. '========== ⇩(4) LargeChange値設定用スクロールバー ============
  12. Private Sub ScrollBar3_Change()
  13.  Me.ScrollBar5.LargeChange = Me.ScrollBar3.Value
  14.  Me.Range("E3") = Me.ScrollBar3.Value
  15. End Sub
  16. '========== ⇩(5) SmallChange値設定用スクロールバー ============
  17. Private Sub ScrollBar4_Change()
  18.  Me.ScrollBar5.SmallChange = Me.ScrollBar4.Value
  19.  Me.Range("E4") = Me.ScrollBar4.Value
  20. End Sub
図15


「Max値設定用スクロールバー」の値が変化した時には、21~24行目のChangeイベントプロシージャが実行されます。
22行目「Me.ScrollBar5.Max = Me.ScrollBar1.Value」では、確認用スクロールバー(ScrollBar5)のMax値を設定用スクロールバーのValue値に変更します。
23行目「Me.Range("E1") = Me.ScrollBar1.Value」では、変更した値(確認用スクロールバーのMax値)を黄色セル(E1セル)に書き出します。

寄り道
なお、スクロールバーの「LinkedCell」プロパティに、例えば「$E$1」等と「Value値を書き込むセル」を指定しておくと、23行目の様な「セルに書き込むコードが不要」になります。但しスクロールバーのValue値がマイナス値の時、例えば「-1」の時には「65535」という変な値が出力されてしまいます。
この現象はバグには違いないのですが、この「-1」の時に出力される65535を二進数で表すと「1111 1111 1111 1111」となります。

コンピュータでマイナスの数を表す時には補数を用います。補数には「1の補数」と「2の補数」がありますが、今回の数値から見ると、ここでは「2の補数」を使用しているようです。
2の補数を使ってマイナス値を求める時には、図16のように「使用しているビット数の最大値に1を足した数」から「正の値」を引き算します。

2の補数を使ったマイナス値の計算方法
図16


例えば、16ビットでの「-1」を求めるには、16ビットの最大値「1111 1111 1111 1111」に1を足した「1 0000 0000 0000 0000」から、求める「-1」を正の値にした「+1」の「0000 0000 0000 0001」を引き算します。
得られた「1111 1111 1111 1111」が「-1」を表すことになります。

この計算方法は、コンピュータにとっては非常に便利です。例えば「1 - 1 =」という計算をしようとした時、「+1」は16ビットでの二進数で「0000 0000 0000 0001」、「-1」は「1111 1111 1111 1111」ですので、その2つを「足し算」すると「1 0000 0000 0000 0000」になります。しかし16ビットで処理していますので、一番上の桁のあふれた「1」は無視され「0000 0000 0000 0000」となり、これは「0」を示します。つまり「1 - 1 = 0」というコンピュータにとって苦手な引き算が、得意な足し算で可能になるのです。

なお、図16では「16ビット(=2バイト =Integer型相当)」で計算していますが、スクロールバーで扱える値はLong型(4バイト=32ビット)です。
この矛盾から「この先はどうなるんだろう?」と思い、真のValue値とLinkedCellへの出力値を並べてみたのが図17です。
Value値とLinkedCell値の違い
図17


結果は、-32768まで行ったら「その先は正常な値を出力」することが分かりました。この分岐点は、VBAのInteger相当(プラスマイナスのある16ビット)の範囲「-32768 ~ 32767」から頷けるものですが、同じ数値(図17の赤字部分)が2度出てくるようなものは使えませんし、セルでの数式による変換も不可能です。
ですので「マイナス側の設定をする可能性のあるスクロールバーでは、LinkedCellプロパティは使わない」事が重要です。

Max値設定用スクロールバーと同様に、Min値設定用スクロールバーの値が変化した時には27~30行目が実行され「確認用スクロールバーのMin値を変更」します。
LargeChange用(33~36行目)、SmallChange用(39~42行目)も同様に、確認用スクロールバーのLargeChange値、SmallChange値を変更します。

4ー2ー3.確認用スクロールバーのValue値表示

確認用スクロールバーの値を変更した時には、図18のChangeイベントプロシージャが呼び出されます。
  1. '========== ⇩(6)  ============
  2. Private Sub ScrollBar5_Change()
  3.  Me.Range("H4") = Me.ScrollBar5.Value
  4. End Sub
図18


52行目「Me.Range("H4") = Me.ScrollBar5.Value」で、Value値を黄色セル(H4セル)に書き出します。

5.まとめ

上記の現象を踏まえると、スクロールバーの設定を動的に行う時には以下のような注意が必要です。
 ・ LargeChange値を一定にすると、Max値とMin値の差が小さい時に「スクロールボックスが消える」
 ・ LargeChangeやSmallChange値を計算で設定する時、ゼロが出る計算式を使うと「スクロール矢印やシャフト部での値変更が出来なくなる」

アプリ実例・関連する項目

グラフのX軸をスクロールバーで移動
スクロールバー種類別・操作別の値取得方法

サンプルファイル

スクロールバー動的設定時の注意点(its-035.xlsm)
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始)
解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。