ステータスバーを作成してみる

ステータスバー

今回はコモンコントロールの1つ、ステータスバーを使ってみたいと思います。ステータスバーは、ステータスウィンドウとも呼ばれます。このコントロールは、ウィンドウの下にある細長いバーで、情報などを表示するときに使われます。

ステータスバー作成の手順

ステータスバーを作成する手順は、以下のようになります。

  1. InitCommonControls 関数を呼び出して、コモンコントロールライブラリを初期化する
  2. クラス名を "msctls_statusbar32" として CreateWindowEx 関数を呼び出す
  3. ステータスバーに SB_SETPARTS メッセージを送信し、ステータスバーを必要な数だけのパーツに分ける
  4. ステータスバーに SB_SETTEXT メッセージを送信し、それぞれのパーツに文字列を表示する

コモンコントロールライブラリの初期化

まずはコモンコントロールライブラリを初期化するために、プログラムの最初に InitCommonControls 関数を呼び出さなければなりません。

InitCommonControls 関数は、コモンコントロールを使用する場合には必ず一度は呼び出す必要があります。複数のステータスバーや、他のコモンコントロールも合わせて使用したい場合には、最初に一度だけ呼び出せばOKです。また、何回でも呼び出すことができるので、コモンコントロールを作成するたびに呼び出したとしても問題はありません。

ステータスバーの作成

ステータスバーの作成には、ウィンドウ作成関数である CreateWindowEx 関数を使います。クラス名として "msctls_statusbar32" を指定することで、ステータスバーを作成できます。

ウィンドウスタイルについては、指定されたウィンドウに対する子ウィンドウとして作成するので、ウィンドウスタイルに 0x40000000(WS_CHILD スタイル)を指定する必要があります。また、はじめから可視状態で作成するために、 0x10000000(WS_VISIBLE スタイル)も合わせて指定しておきます。さらに、ステータスバーを親ウィンドウの下端に配置するので、0x00000003(CCS_BOTTOM スタイル)も指定する必要があります。

ウィンドウの位置とサイズについてですが、ウィンドウスタイルに CCS_BOTTOM を指定しておけば、親ウィンドウのサイズなどから自動的に計算されて親ウィンドウの下端に移動されるので、位置・サイズを指定するパラメータには 0 を指定しておけばよいでしょう。

ステータスバーが作成されると、この関数から作成されたステータスバーのウィンドウハンドルが返ります。これは、単にステータスバーのハンドルとも呼ばれます。

パーツの作成

ステータスバーを作成したら、ステータスバーに SB_SETPARTS メッセージを送信して、ステータスバーを複数のパーツに分けるように指定します。

#define  SB_SETPARTS    0x0404

SB_SETPARTS
    wParam = nParts;
    lParam = aWidths;

nParts パラメータには、ステータスバーをいくつのパーツに分けるのかを指定します。 255 以上の値を指定することはできません。

aWidths パラメータには、各パーツの位置(右端のx座標)を格納した配列変数のアドレスを指定します。また、パーツ位置を -1 とすれば、ステータスバーの右端までが指定されます。

例えば、3つのパーツを作成して、それぞれの幅を 100, 50, 80 としたいとき、それぞれのパーツの右端のx座標は 100, 150, 230 となるので、

partspos = 100, 150, 230  ; パーツの位置を入れた配列変数

pm.0 = hStatus            ; ステータスバーのハンドル
pm.1 = 0x0404             ; SB_SETPARTS
pm.2 = 3                  ; パーツの数
getptr pm.3, partspos     ; 配列変数のアドレス
sendmsg pm                ; メッセージ送信

というようにします。

パーツの表示文字列の設定

ステータスバーのそれぞれのパーツに表示される文字列を設定するには、 SB_SETTEXT メッセージを送ります。

#define  SB_SETTEXT    0x0401

SB_SETTEXT
    wParam = iPart | uType;
    lParam = pszText;

iPart パラメータにはパーツのインデックスを指定します。どのパーツの文字列を設定するのかを指定します。例えば、最も左側のパーツの文字列を設定するには 0 を、その右隣の文字列を設定する場合には 1 を指定します。

uType パラメータにはパーツの表示形式を指定します。 0 を指定するとテキスト表示領域がくぼんで表示され、0x0200 (SBT_POPOUT) を指定すると浮き上がって表示されます。0x100 (SBT_NOBORDERS) を指定するとテキスト表示領域の境界は表示されません。

pszText パラメータには、表示させる文字列を格納した変数のアドレスを指定します。この文字列のサイズは127バイト以下でなければなりません。


実は、ステータスバーのパーツに表示するテキストは、パーツのどの部分に表示するか(左揃え/中央揃え/右揃え)を指定することができます。

テキストをそのまま指定すると、左揃えで表示されます。

テキストの直前にタブ文字("\t")を1つだけ付けると、中央揃えで表示されます。

テキストの直前にタブ文字("\t")を2つ続けて付けると、右揃えで表示されます。

msgtext.0 = "パーツ1"             ; 左揃えで表示
msgtext.1 = "\tパーツ2"           ; 中央揃えで表示
msgtext.2 = "\t\tパーツ3"         ; 右揃えで表示

サンプルスクリプト

さて、実際にスクリプトを書いてみましょう。

    #include "llmod.as"
    #include "hsgetmsg.as"

    ; コモンコントロールライブラリの初期化
    dllproc "InitCommonControls", pm, 0, D_COMCTL

    ; ステータスバーの作成
    mref bmscr, 67                     ; 描画中ウィンドウのBMSCR構造体
    classname = "msctls_statusbar32"   ; ステータスバーのウィンドウクラス
    pm.0 = 0
    getptr pm.1, classname
    pm.2 = 0
    pm.3 = 0x50000003                  ; WS_VISIBLE | WS_CHILD | CCS_BOTTOM
    pm.4 = 0, 0, 0, 0                  ; 位置・サイズはすべて 0 を指定
    pm.8 = bmscr.13                    ; 親ウィンドウのハンドル
    pm.9 = 1                           ; コントロールID
    pm.10 = bmscr.14                   ; インスタンスハンドル
    pm.11 = 0                          ; NULL
    dllproc "CreateWindowExA", pm, 12, D_USER
    hStatus = stat                     ; ステータスバーのウィンドウハンドル

    ; ステータスバーを3つのパーツに分ける
    partspos = 50, 120, -1             ; パーツの位置( -1 のとき右端まで表示)
    ; SB_SETPARTS メッセージ送信
    pm = hStatus, $404, 3
    getptr pm.3, partspos
    sendmsg pm

    ; パーツの表示テキストを設定
    sdim msgtext , 128, 3
    msgtext.0 = "パーツ1"             ; 左揃えで表示
    msgtext.1 = "\tパーツ2"           ; 中央揃えで表示
    msgtext.2 = "\t\tパーツ3"         ; 右揃えで表示
    repeat 3
        ; SB_SETTEXT メッセージ送信
        pm = hStatus, $401, cnt
        getptr pm.3, msgtext.cnt
        sendmsg pm
    loop

    stop

ウィンドウサイズの変更について

親ウィンドウが width 命令などによってサイズ変更された場合、そのままではステータスバーの表示位置は変わりません。これは、親ウィンドウのサイズが変更されたということが、子ウィンドウであるステータスバーに伝わっていないからなのです。そこで、ステータスバーにサイズ変更通知をする必要があります。そのためには、ステータスバーに WM_SIZE メッセージを送信します。

#define  WM_SIZE    0x0005

WM_SIZE
    wParam = fwSizeType;
    lParam = nWidth | (nHeight << 16);

このメッセージは本来、ウィンドウサイズが変更されたときに送られるメッセージなのですが、親ウィンドウサイズが変更されたことをコントロールに知らせるためにも使用することができます。

fwSizeType パラメータは、どのようにサイズ変更がなされたのかのフラグを表します。ここでは 0 を指定すればよいでしょう。 nWidth パラメータおよび nHeight パラメータは、ウィンドウの新しいクライアントサイズを表します。基本的にステータスバーは親ウィンドウのサイズに合わせて自動的にサイズが決定されるので、どちらも 0 でかまいません。とにかく、ウィンドウサイズ変更をしたら、このメッセージをステータスバーに送るようにしましょう。

; WM_SIZE メッセージの送信
pm = hStatus, 0x0005, 0, 0
sendmsg pm

ステータスバーの高さについて

ステータスバーは、ウィンドウ上に子ウィンドウとして貼り付けるという形をとっているため、親ウィンドウのクライアント領域のうち、ステータスバーの下に描画されている部分は見えなくなってしまいます。そのため、プログラム上でそのことを考慮してウィンドウ描画を行なっていく必要があります。そこで、ステータスバーの高さを取得する必要が出てきますね。その方法を説明します。

ステータスバーはウィンドウのひとつなので、 GetWindowRect 関数でウィンドウの座標を取得することができます。この関数はウィンドウの左上および右下の座標を取得するものなので、右下y座標と左上y座標の差を求めることで、ステータスバーの高さを求めることができます。

pm.0 = hStatus                ; ステータスバーのハンドル
getptr pm.1, rect             ; 変数 rect (RECT構造体)のアドレス
dllproc "GetWindowRect", pm, 2, D_USER
nheight = rect.3 - rect.1     ; 高さの取得