ツールバーを作成してみる ACT-3

ツールボタンの状態の変更

今回は、ツールバーのボタンの状態を取得したり設定したりしてみましょう。これらの作業はすべてツールバーにメッセージを送ることによって行なうことができます。

状態の取得

ツールバーのボタンの状態を取得するには、ツールバーに TB_GETSTATE メッセージを送信します。

#define TB_GETSTATE        0x0412

TB_GETSTATE
    wParam = idButton;
    lParam = 0;

idButton パラメータには、状態を取得するツールボタンのコマンドIDを指定します。このメッセージを送ると、戻り値として指定されたボタンの現在の状態が取得されます。ボタンの状態には例として以下のようなものがあり、状態はこれらの値の組み合わせで取得されます。

意味
0x01 (TBSTATE_CHECKED) ボタンが TBSTYLE_CHECK スタイルを持っていて、押されている状態。
0x02 (TBSTATE_PRESSED) ボタンが押されている状態。
0x04 (TBSTATE_ENABLED) ボタンが使用可能な状態。この状態が指定されていない場合はボタンは灰色表示になり、使用不可になります。
0x08 (TBSTATE_HIDDEN) ボタンが見えない状態。ユーザーからの入力を受け付けません。
0x10 (TBSTATE_INDETERMINATE) ボタンが灰色表示の状態。
0x20 (TBSTATE_WRAP) ボタンを次の行に表示。TBSTATE_ENABLED が同時に指定されている必要があります。

状態の設定

ボタンの状態を設定するには、ツールバーに TB_SETSTATE メッセージを送ります。

#define TB_SETSTATE        0x0411

TB_GETSTATE
    wParam = idButton;
    lParam = fState;

idButton パラメータには、状態を取得するツールボタンのコマンドIDを、 fState パラメータには設定する状態を指定します。状態は上の表で示した値の組み合わせで指定します。


状態の設定は、それぞれの属性に対してのみ行なうこともできます。例えば、ボタンの表示・非表示を設定したり、有効・無効を設定したりすることができます。

表示・非表示の設定

ボタンの表示・非表示を設定するには、ツールバーに TB_HIDEBUTTON メッセージを送ります。

#define TB_HIDEBUTTON        0x0404

TB_HIDEBUTTON
    wParam = idButton;
    lParam = fHide;

idButton パラメータには、表示・非表示の状態を設定するツールボタンのコマンドIDを、 fHide パラメータには、ボタンを表示する場合は 0 (FALSE) を、非表示にする場合は 1 (TRUE) をそれぞれ指定します。

有効・無効の設定

ボタンを押せないように無効にしたり、逆に有効にしたりするには、ツールバーに TB_ENABLEBUTTON メッセージを送ります。

#define TB_ENABLEBUTTON        0x0401

TB_ENABLEBUTTON
    wParam = idButton;
    lParam = fEnable;

idButton パラメータには、有効・無効の状態を設定するツールボタンのコマンドIDを、 fEnable パラメータには、ボタンを有効にする場合は 1 (TRUE) を、無効にする場合は 0 (FALSE) をそれぞれ指定します。無効にすると、ボタンが灰色表示になってユーザーはボタンを押すことができなくなります。

押されている状態・押されていない状態の設定

ボタン追加時にボタンのスタイルに 0x0002 (TBSTYLE_CHECK スタイル) を指定してある場合、ボタンが押されている状態と押されていない状態とを切りかえることができます。この設定をするには、ツールバーに TB_CHECKBUTTON メッセージを送ります。

#define TB_CHECKBUTTON         0x0402

TB_CHECKBUTTON
    wParam = idButton;
    lParam = fCheck;

idButton パラメータには、状態を設定するツールボタンのコマンドIDを、 fCheck パラメータには、ボタンを押された状態にする場合は 1 (TRUE) を、押されていない状態にする場合は 0 (FALSE) をそれぞれ指定します。

サンプルスクリプト

さて、実際にスクリプトを書いてみます。今回のサンプルはちょっとパズルゲーム感覚のものにしてみました。

スクリプト中では、ボタンの状態を取得・変更するのに TB_GETSTATE メッセージと TB_ENABLEBUTTON メッセージを使用しています。

今回使用する画像ファイルは、前に使用したのと同じものを使います。このビットマップファイルは、それぞれのイメージサイズが 16×15 ピクセル、イメージ数が9個、背景色の白色がパレットコードの 0 になるように作られた256色ビットマップファイルです。

(toolbtn.bmp)

ビットマップファイルのダウンロード

今回は、ビットマップオブジェクトの作成と、ツールバーの操作の部分をモジュール命令として定義してあります。

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

    #module ;####### ビットマップオブジェクト作成モジュール #########

    ;===============================================================
    ; 描画中ウィンドウのイメージからビットマップオブジェクト作成
    ; CreateBitmap  p1, p2, p3, p4
    ;     p1 : HSPウィンドウx座標
    ;     p2 : HSPウィンドウy座標
    ;     p3 : 幅
    ;     p4 : 高さ
    ;   stat : ビットマップのハンドルが返る
    ;===============================================================
    #deffunc CreateBitmap int, int, int, int
    mref px, 0              ; HSPウィンドウx座標
    mref py, 1              ; HSPウィンドウy座標
    mref sx, 2              ; xサイズ
    mref sy, 3              ; yサイズ
    mref stt, 64            ; stat
    mref bmscr, 67          ; 描画中ウィンドウのBMSCR構造体

    ; ディスプレイのデバイスコンテキストのハンドル取得
    devname = "DISPLAY"
    pm = 0,0,0,0
    getptr pm, devname      ; "DISPLAY"のアドレス
    dllproc "CreateDCA", pm, 4, D_GDI@
    hdcScreen = stat        ; ディスプレイのデバイスコンテキスト

    ; ディスプレイ互換ビットマップオブジェクト作成
    pm = hdcScreen, sx, sy
    dllproc "CreateCompatibleBitmap", pm, 3, D_GDI@
    hbitmap = stat          ; ビットマップオブジェクトのハンドル

    ; ディスプレイ互換デバイスコンテキスト作成
    pm = hdcScreen
    dllproc "CreateCompatibleDC", pm, 1, D_GDI@
    hdcMemory = stat        ; メモリデバイスコンテキストのハンドル

    ; ビットマップをデバイスコンテキストに選択
    pm = hdcMemory, hbitmap
    dllproc "SelectObject", pm, 2, D_GDI@
    ; HSPウィンドウからビットマップにイメージをコピー
    pm = hdcMemory, 0, 0, sx, sy, bmscr.4, px, py, $CC0020
    dllproc "BitBlt", pm, 9, D_GDI@

    ; デバイスコンテキストを削除
    dllproc "DeleteDC", hdcMemory, 1, D_GDI@
    dllproc "DeleteDC", hdcScreen, 1, D_GDI@

    stt = hbitmap           ; ビットマップオブジェクトのハンドル
    return

    #global ;############# モジュール終わり ########################

    #module ;########### ツールバー操作モジュール ##################

    ;===============================================================
    ; ツールバー作成
    ; CreateToolbar  p1, p2
    ;     p1 : ボタンイメージの幅 (0のとき16ピクセル)
    ;     p2 : ボタンイメージの高さ (0のとき15ピクセル)
    ;   stat : ツールバーのハンドルが返る
    ;===============================================================
    #deffunc CreateToolBar int, int
    mref sx, 0              ; ビットマップの数
    mref sy, 1              ; ビットマップオブジェクトのハンドル
    mref stt, 64            ; stat

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

    ; ツールバー作成
    pm = 0, 0, 0, 0         ; 座標・サイズは 0 でよい
    pm.4 = 0x50000001       ; WS_CHILD | WS_VISIBLE | CCS_NORESIZE
    pm.5 = 0, 0
    _makewnd pm, "ToolbarWindow32"
    hTool = pm              ; ツールバーのハンドル

    ; TB_BUTTONSTRUCTSIZE メッセージ送信
    pm = hTool, 0x041E, 20, 0
    sendmsg pm

    ; ビットマップのサイズを設定
    if sx == 0 : sx = 16
    if sy == 0 : sy = 15
    ; TB_SETBITMAPSIZE メッセージ送信
    pm = hTool, 0x420, 0, sx | (sy << 16)
    sendmsg pm

    stt = hTool              ; stat にツールバーのハンドルを格納
    return

    ;===============================================================
    ; 描画中ウィンドウのイメージをツールバーに加える
    ; (パレットモードであること・パレットインデックス 0 は透過色)
    ; (イメージが複数のときは横に並べられていること)
    ; AddToolBitmap  p1, p2
    ;     p1 : ツールバーのハンドル
    ;     p1 : HSPウィンドウx座標
    ;     p2 : HSPウィンドウy座標
    ;     p3 : 幅
    ;     p4 : 高さ
    ;   stat : 最初のイメージのインデックスが返る
    ;===============================================================
    #deffunc AddToolBitmap int, int, int, int, int
    mref hTool, 0           ; ツールバーのハンドル
    mref px, 0              ; HSPウィンドウx座標
    mref py, 1              ; HSPウィンドウy座標
    mref sx, 2              ; 高さ
    mref sy, 3              ; 幅
    mref stt, 64            ; stat

    ; パレット 0 をシステムカラーのボタン表面色に変更
    pm = 15                     ; COLOR_BTNFACE
    dllproc "GetSysColor", pm, 1, D_USER@
    palette 0, stat&$FF, (stat>>8)&$FF, (stat>>16)&$FF
    palfade

    ; ビットマップオブジェクト作成
    CreateBitmap 0, 0, winx, winy
    hbitmap = stat                 ; ビットマップのハンドル

    ; ビットマップをボタンイメージのリストに追加
    ; TBADDBITMAP 構造体
    tbadd.0 = 0
    tbadd.1 = hbitmap           ; ビットマップハンドル

    ;TB_ADDBITMAPメッセージを送信
    pm = hTool, 0x0413
    pm.2 = 9                    ; ビットマップ中のボタンイメージの数
    getptr pm.3, tbadd          ; TBADDBITMAP 構造体のアドレス
    sendmsg pm
    index = stat

    ; ビットマップオブジェクトを削除
    dllproc "DeleteObject", hbitmap, 1, D_GDI@

    stt = index
    return

    ;===============================================================
    ; ボタンを1個追加
    ; AddToolButton  p1, p2, p3, p4, p5
    ;    p1 : ツールバーのハンドル
    ;    p2 : ボタンのイメージのインデックス
    ;    p3 : コマンドID
    ;    p4 : ボタンの状態(使用可能ボタンは4が必要)
    ;    p5 : ボタンスタイル
    ;===============================================================
    #deffunc AddToolButton int, int, int, int, int
    mref hTool, 0           ; ツールバーのハンドル
    mref index, 1           ; ボタンのイメージのインデックス
    mref idCmd, 2           ; コマンドID
    mref fsState, 3         ; ボタン状態
    mref fsStyle, 4         ; ボタン

    ; TBBUTTON 構造体
    tbb.0 = index                       ; ボタンのイメージのインデックス
    tbb.1 = idCmd                       ; コマンドID
    tbb.2 = fsState | (fsStyle << 8)    ; ボタン状態・スタイル
    tbb.3 = 0
    tbb.4 = 0

    ; TB_ADDBUTTONS メッセージを送信
    pm = hTool, 0x0414
    pm.2 = 1                ; 追加するボタンの数(1個)
    getptr pm.3, tbb        ; TBBUTTON 構造体のアドレス
    sendmsg pm

    ; TB_AUTOSIZE メッセージ送信
    pm = hTool, 0x0421, 0, 0
    sendmsg pm
    return

    ;===============================================================
    ; ボタンのスタイル取得
    ; GetToolState  p1, p2
    ;    p1 : ツールバーのハンドル
    ;    p2 : コマンドID
    ;  stat : 取得したスタイルが返る
    ;===============================================================
    #deffunc GetToolState int, int
    mref hTool, 0           ; ツールバーのハンドル
    mref cmdID, 1           ; ボタンのコマンドID

    ; TB_GETSTATE メッセージを送信
    pm = hTool, 0x0412, cmdID, 0
    sendmsg pm
    return

    ;===============================================================
    ; ボタンの有効・無効を設定
    ; EnableToolButton  p1, p2, p3
    ;    p1 : ツールバーのハンドル
    ;    p2 : コマンドID
    ;    p3 : 1:有効  0:無効
    ;===============================================================
    #deffunc EnableToolButton int, int, int
    mref hTool, 0
    mref cmdID, 1
    mref fEnable, 2

    ; TB_TB_ENABLEBUTTON メッセージを送信
    pm = hTool, 0x0401, cmdID, fEnable
    sendmsg pm
    return

    ;===============================================================
    ; ツールバーの高さを取得
    ; GetToolHeight  p1
    ;    p1 : ツールバーのハンドル
    ;  stat : ツールバーの高さが返る
    ;===============================================================
    #deffunc GetToolHeight int
    mref hTool, 0                 ; ツールバーのハンドル
    mref stt, 64                  ; stat

    pm.0 = hTool                  ; ツールバーのハンドル
    getptr pm.1, rect             ; RECT 構造体のアドレス
    dllproc "GetWindowRect", pm, 2, D_USER@
    stt = rect.3 - rect.1         ; 高さを求める
    return

    #global ;############# モジュール終わり ########################


    screen 0, 250, 130

    ; ツールバーの作成
    CreateToolbar 16, 15          ; イメージのサイズ 16×15
    hTool = stat                  ; ツールバーのハンドル

    ; ボタンイメージ
    buffer 2,,,1                   ; パレットモードで初期化
    picload "toolbtn.bmp"          ; パレットインデックス 0 が透過色
    AddToolBitmap  hTool, 0, 0, 16*5, 15

    ; 5個のボタンを追加(コマンドID = 1000〜1004)
    repeat 5
        AddToolButton  hTool, cnt, 1000+cnt, 4
    loop

    ; ウィンドウのサブクラス化
    gsel 0
    set_subclass                ; サブクラス化
    hwnd = stat                 ; メインウィンドウのハンドル
    set_message 0x0111          ; WM_COMMAND を取得するように設定
    ; メッセージパラメータ用変数
    dup msg,  msgval.1          ; メッセージが格納される変数
    dup wprm, msgval.2          ; wParamパラメータが格納される変数
    dup lprm, msgval.3          ; lParamパラメータが格納される変数

    GetToolHeight hTool         ; ツールバーの高さ取得
    pos 0, stat
    mes {"
        すべてのボタンを選択不可の状態
        にしてみよう。
        ボタンを押すと押されたボタンと
        その両側のボタンの選択可・不可
        の状態が切り替わります。
    "}

    cPush = 0                   ; ボタンを押した回数

*mainloop
    get_message msgval
    if msgval == hwnd {
        if msg == 0x0111 : gosub *onCommand
    } else {
        wait 10
    }
    goto *mainloop

*onCommand
    ; WM_COMMANDが送られたとき
    ; ツールバー以外から送られた場合は何もしない
    if lprm != hTool : return

    cmdID = wprm & 0xFFFF       ; 押されたボタンのコマンドID

    ; ボタン3つの状態(有効・無効)を変化させる
    repeat 3
        cmdID2 = cmdID + cnt - 1
        if cmdID2 < 1000 : cmdID2 += 5
        if cmdID2 > 1004 : cmdID2 -= 5
        GetToolState hTool, cmdID2
        if stat & 0x04 {        ; ボタンが有効の時は無効にする
            EnableToolButton hTool, cmdID2, 0
        } else {                ; ボタンが無効の時は有効にする
            EnableToolButton hTool, cmdID2, 1
        }
    loop
    cPush++

    ; すべて無効になったかどうかの確認
    flag = 0
    repeat 5
         GetToolState hTool, 1000+cnt
         if stat & 0x04 : flag = 1 : break
    loop
    if flag == 0 {
        dialog "おめでとー!!\nボタンを押した回数 : "+cPush
        end
    }
    return

5つのボタンが最初はすべて有効な状態になっていて、ボタンを押すと、そのボタンとその両側にあるボタン(端のボタンが押された場合は反対側の端のボタンも)の有効・無効の状態が入れ替わるようになっています。すべてのボタンを無効の状態にすることができれば終了です。

最短で7回でできるはずです。