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

ツールボタンの文字列

今回は、ツールバーのボタンにのイメージの下に文字列を表示してみます。


ツールバーは内部にボタンイメージのリストを持っていて、表示させるイメージはそのリスト中のものが使われるということは以前に説明しました。ツールバーに表示される文字列もこれとまったく同様で、ツールバーは内部に文字列リストを持っており、このリスト中にある文字列が表示されるようになっています。

ボタンに文字列を表示させるには、まず文字列リストの中に表示させる文字列を追加しなくてはいけません。リストに文字列を追加させるには、ツールバーに TB_ADDSTRING メッセージを送信します。

#define TB_ADDSTRING        0x041C

TB_ADDSTRING
    wParam = hinst;
    lParam = idString;

ここでは、 hinst パラメータには 0 (NULL) を、 idString パラメータには文字列を入れたバッファのアドレスをそれぞれ指定します。メッセージ送信時の戻り値として、追加された文字列のリスト中でのインデックスが返ります。

このメッセージでは一度に複数の文字列を追加できるようになっていますが、このとき、それぞれの文字列がヌル文字(すなわち1バイトサイズの 0 )で区切られているように指定し、また、最後の文字列の後には2つのヌル文字がなければなりません。例えば、3つの文字列“Str1”、“Str2”、“Str3”を指定する場合、

Str1 (NUL) Str2 (NUL) Str3 (NUL) (NUL)

というように配置されなければなりません。このとき、メモリ内は

53 74 72 31 00 53 74 72 32 00 53 74 72 33 00 00 (16進数表示)
'S' 't' 'r' '1' NUL 'S' 't' 'r' '2' NUL 'S' 't' 'r' '3' NUL NUL

のようになっていることになります。バッファにこのように格納させるには、以下に示すような方法をを使います。

sdim buf, 64
sdim s, 8, 3
s.0 = "Str1"
s.1 = "Str2"
s.2 = "Str3"
idx = 0
repeat 3
    poke buf, idx, s.cnt
    idx += strsize
    poke buf, idx, 0        ; NULL文字で区切る
    idx++
loop
poke buf, idx, 0            ; 最後の2個目のヌル文字

とすれば、変数 buf には上で示したような形で格納されます。(話はそれますが、 (w)poke 命令を使うときに文字列を指定すると、バッファに書きこまれた文字列のサイズがシステム変数 strsize に格納されます。マニュアルには載っていないようですが。ここではそれを使っています。)

上のように一度に複数の文字列を追加するよりは、1つずつ順番に追加していくほうが簡単だと思います。1つずつ追加する場合も、文字列の後ろに2つのヌル文字が続かなくてはならないので、 sdim である程度余裕を持って確保しておいた変数に入れてそれを指定しましょう。

文字列リストの中に文字列を追加できたら、あとは TB_ADDBUTTONS メッセージや TB_INSERTBUTTON メッセージでボタンを追加する際に、 TBBUTTON 構造体の iString メンバに文字列のリスト中におけるインデックスを指定すれば、文字列が表示されたボタンがツールバーに追加されます。

サンプルスクリプト

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

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

(toolbtn2.bmp)

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

サンプルスクリプト main.as

    #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

    ;===============================================================
    ; テキストをツールバーの文字列リストに加える
    ; AddToolString  p1, p2
    ;    p1 : ツールバーのハンドル
    ;    p2 : 文字列(複数ある場合は改行("\n")で区切る)
    ;  stat : 文字列インデックスが返る
    ;===============================================================
    #deffunc AddToolString int, str
    mref hTool, 0           ; ツールバーのハンドル
    mref setStr, 33         ; リストに加える文字列
    mref stt, 64            ; stat

    strlen ln, setStr
    sdim szString, ln+1
    sdim temp, 64

    ; メモリノートパッド命令を使う
    notesel setStr
    notemax num
    index = 0
    ; ヌル文字で区切る
    repeat num
        noteget temp, cnt
        poke szString, index, temp : index += strsize
        poke szString, index, 0    : index++
    loop
    poke szString, index, 0         ; 最後の2個目のヌル文字

    ; TB_ADDSTRING メッセージ送信
    pm = hTool, 0x041C, 0
    getptr pm.3, szString
    sendmsg pm
    return

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

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

    ; 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

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


    screen 0, 310, 110

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

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

    ; 文字列リストへの追加
    AddToolString hTool, "新規\n開く\n保存\n切り取り\nコピー\n貼り付け"

    ; 6個のボタンを追加
    AddToolButton hTool, 0, 1000, 0x04, 0x00, 0
    AddToolButton hTool, 1, 1001, 0x04, 0x00, 1
    AddToolButton hTool, 2, 1002, 0x04, 0x00, 2
    AddToolButton hTool, 0,    0,    0, 0x01, 0
    AddToolButton hTool, 3, 1003, 0x04, 0x00, 3
    AddToolButton hTool, 4, 1004, 0x04, 0x00, 4
    AddToolButton hTool, 5, 1005, 0x04, 0x00, 5

    ; ウィンドウのサブクラス化
    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パラメータが格納される変数

*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
    if (cmdID >= 1000) & (cmdID <= 1005) {
        if cmdID == 1000 : s = "新規"
        if cmdID == 1001 : s = "開く"
        if cmdID == 1002 : s = "保存"
        if cmdID == 1003 : s = "切り取り"
        if cmdID == 1004 : s = "コピー"
        if cmdID == 1005 : s = "貼り付け"
        dialog "\"" +s+ "\"ボタンが押されました"
    }
    return