
今回作成するのは、コモンコントロールの1つであるツールバーです。ツールバーはボタンを持った右図のようなコントロールです。よく見かけるコントロールですね。たいていのWindowsアプリはこのツールバーを持っています。今回はこのツールバーを作成して、ボタンが押されたらそのことをユーザーに通知するようなスクリプトを作ります。
ツールバーを作成する手順は以下のようになります。
まずは、全コモンコントロール共通の InitCommonControls 関数を呼び出します。これによってツールバーのウィンドウクラスが登録されるので、ツールバーを作成できるようになります。
次に CreateWindowEx 関数を呼び出します。このとき、ウィンドウクラス名には "ToolbarWindow32" を指定し、ウィンドウスタイルには WS_CHILD | WS_VISIBL | CCS_TOP を指定します。また、 CCS_NORESIZE スタイルを指定しなければウィンドウの位置やサイズは自動的に決められるので、位置とサイズにはすべて 0 を指定してかまいません。
ツールバーが作成できたら、まずは TB_BUTTONSTRUCTSIZE メッセージを送信しなければなりません。
#define TB_BUTTONSTRUCTSIZE 0x041E
TB_BUTTONSTRUCTSIZE
wParam = 20;
lParam = 0;
このメッセージは、ツールバーに TBBUTTON 構造体のサイズを伝えるためのものです。この構造体のサイズは 20 バイトなので、 wParam パラメータに 20 を指定します。また、 lParam パラメータには 0 を指定してください。
ツールバーは、ボタンに表示するイメージのリストを内部に持っており、ボタンイメージはこのリスト中のものが表示されるようになっています。したがって、イメージをこのリストの中に追加しなくてはなりません。
まずは、イメージのサイズを設定する必要があります。デフォルトでは横16ピクセル、縦15ピクセルになっていますが、それ以外のサイズのイメージを使用する場合には TB_SETBITMAPSIZE メッセージを送信してサイズを設定する必要があります。
#define TB_SETBITMAPSIZE 0x0420
TB_SETBITMAPSIZE
wParam = 0;
lParam = dxBitmap | ( dyBitmap << 16 );
dxBitmap パラメータと dyBitmap パラメータには、それぞれビットマップイメージの幅と高さをピクセル単位で指定します。
次に、表示するイメージのビットマップオブジェクトを作成する必要があります。このビットマップは、ディスプレイ互換のDDBとして作成しましょう。
ディスプレイ互換ビットマップの作成方法については、『ビットマップオブジェクトを作成する』の項を参照してください。
ビットマップの背景となる部分を、システムカラーの3Dオブジェクト色にしておきたいので、まず GetSysColor 関数でシステムカラーを取得し、背景部分をこの色で塗りつぶしておきます。 gmode で透明色付きコピーを指定すればできると思いますが、ここでは手間を省くために、ビットマップファイルを256色で作成し、パレットモードで初期化したバッファウィンドウに読み込んで、 palette 命令で透明色用のパレットインデックスの色をシステムカラーに設定するという方法を使いましょう。
例えば、ビットマップイメージとして背景色がパレットコードの 0 になるように作られた256色ビットマップファイルを使う場合、
; 画像のロード buffer 2,,, 1 ; パレットモードで初期化 picload "toolbtn.bmp" ; パレット 0 をシステムカラーのボタン表面色に変更 pm = 15 ; COLOR_BTNFACE dllproc "GetSysColor", pm, 1, D_USER palette 0, stat&$FF, (stat>>8)&$FF, (stat>>16)&$FF palfade
というようにします。
ビットマップが作成できたら、これをリストに追加します。これには、 TBADDBITMAP 構造体にビットマップの情報を格納して TB_ADDBITMAP メッセージを送信します。
typedef struct {
HINSTANCE hInst; // モジュールのインスタンスハンドル
UINT nID; // リソースIDまたはビットマップハンドル
} TBADDBITMAP, *LPTBADDBITMAP;
hInst メンバは、ここでは 0 (NULL) を指定します。 nID メンバに、作成したビットマップのハンドルを指定します。
#define TB_ADDBITMAP 0x0413
TB_ADDBITMAP
wParam = nButtons;
lParam = ptbadd;
nButtons パラメータには、ビットマップ中に含まれるボタンイメージの数を指定します。 ptbadd パラメータには、情報を格納した TBADDBITMAP 構造体のアドレスを指定します。 TB_ADDBITMAP メッセージを送信すると、戻り値として、追加されたイメージのリスト中でのインデックスが返ります。一番最初に追加されたイメージのインデックスは 0 になります。また、一度に複数のイメージを追加した場合には、1番目のイメージのインデックスが返ります。
イメージをリストに追加できたら、ボタンを追加します。ボタンを追加するには、 TBBUTTON 構造体に追加するボタンの情報を格納して、ツールバーに TB_ADDBUTTONS メッセージまたは TB_INSERTBUTTON メッセージを送ります。
TBBUTTON 構造体は以下のように定義されています。
typedef struct _TBBUTTON {
int iBitmap; // ビットマップのインデックス
int idCommand; // コマンドID
BYTE fsState; // ボタンの状態
BYTE fsStyle; // ボタンのスタイル
BYTE bReserved[2] // 予約(= 0 )
DWORD_PTR dwData; // アプリケーション定義値
INT_PTR iString; // テキストのインデックス
} TBBUTTON, NEAR* PTBBUTTON, FAR* LPTBBUTTON;
iBitmap メンバには、ボタンに表示させるイメージの、リスト中でのインデックスを指定します。
idCommand メンバには、ボタンが押されたときに親ウィンドウに送られる WM_COMMAND メッセージのパラメータとして含まれるコマンドIDを指定します。
fsState メンバにはボタンの状態を指定します。このメンバに 0x04 (TBSTATE_ENABLED) を指定していなければボタンが表示されないので注意してください。
fsStyle メンバにはボタンのスタイルを指定します。
dwData メンバにはアプリケーション定義の32ビット値を指定します。
iString メンバはボタンに表示させる文字列の、リスト中でのインデックスを指定します。今回は使用しません。
TB_ADDBUTTONS メッセージは、指定したツールバーの最後にボタンを追加します。このメッセージは、同時に複数個のボタンを追加することができます。
#define TB_ADDBUTTONS 0x0414
TB_ADDBUTTONS
wParam = nNumButtons;
lParam = lpButtons;
nNumButtons パラメータには追加するボタンの数を、 lpButtons パラメータにはその数だけの要素を持つ TBBUTTON 構造体の配列のアドレスを指定します。 TBBUTTON 構造体のサイズは20バイトであるので、数値型配列変数に格納する場合には5要素ずつ区切られます。例えば、数値型変数 tbb にとったとき、
というようになります。
TB_INSERTBUTTON メッセージは、ツールバー上の指定した位置に1個のボタンを挿入します。
#define TB_INSERTBUTTON 0x0415
TB_INSERTBUTTON
wParam = iButton;
lParam = lpButton;
iButton パラメータには、ボタンを挿入する位置のインデックスを指定します。このインデックスで指定されたボタンの右側に新しいボタンが挿入されます。 lpButton パラメータには、ボタンの情報を格納した TBBUTTON 構造体のアドレスを指定します。
最後に、ツールバーに TB_AUTOSIZE メッセージを送信して、ツールバーのサイズを調整します。このメッセージにより、ボタンのサイズに合わせてツールバーの高さが変更されます。
#define TB_AUTOSIZE 0x0421
TB_AUTOSIZE
wParam = 0;
lParam = 0;
以上の操作で、ツールバーの作成が完了します。あとは、メインループ中でメッセージが送られてくるのを監視します。ツールバーのボタンが押されると、親ウィンドウに WM_COMMAND メッセージが送られてきます。このときの wParam パラメータの下位ワードは、ボタンに設定したコマンドIDになります。また、 lParam パラメータにはツールバーのハンドルが格納されます。これによって、どのボタンが押されたのかを知ることができます。
さて、実際にスクリプトを書いてみます。ツールバーに表示させるイメージとして下のビットマップを使います。このビットマップファイルは、それぞれのイメージサイズが 16×15 ピクセル、イメージ数が9個、背景色の白色がパレットコードの 0 になるように作られた256色ビットマップファイルです。
(toolbtn.bmp)
以前から幾度となく使用しているビットマップオブジェクト作成モジュールを、今回も使用しています。
#include "llmod.as"
#include "hsgetmsg.as"
#module ;#######################################################
;===============================================================
; CreateBitmap ディスプレイ互換DDBオブジェクト作成
;===============================================================
#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 ;############# モジュール終わり ########################
; コモンコントロールライブラリ初期化
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
; TB_SETBITMAPSIZE メッセージでビットマップのサイズを設定
; (サイズが 16×15 なので、送らなくてもよい)
pm = hTool, 0x420, 0
pm.3 = 16 | ( 15 << 16 ) ; x | (y << 16) を指定
sendmsg pm
; ボタンイメージ用ビットマップファイルのロード
buffer 2,,, 1 ; バッファウィンドウをパレットモードで作成
picload "toolbtn.bmp"
; パレット 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, 16*9, 15
hBitmap = stat ; 作成されたビットマップのハンドル
; ビットマップをボタンイメージのリストに追加
; TBADDBITMAP 構造体
tbadd.0 = 0
tbadd.1 = hBitmap ; ビットマップハンドル
;TB_ADDBITMAPメッセージを送信
pm = hTool, 0x0413
pm.2 = 9 ; ビットマップ中のボタンイメージの数
getptr pm.3, tbadd ; TBADDBITMAP 構造体のアドレス
sendmsg pm
idxImage = stat ; ここでは必ず0になるのであえて保存する必要はない
; ビットマップオブジェクトを削除
dllproc "DeleteObject", hBitmap, 1, D_GDI
; ボタンを追加(ボタンの数だけ繰り返し)
repeat 9
; TBBUTTON 構造体をセット
tbb.0 = idxImage + cnt ; イメージのインデックス
tbb.1 = 1000 + cnt ; コマンドID
tbb.2 = 4 ; fsState=TBSTATE_ENABLED, fsStyle=0
tbb.3 = 0
tbb.4 = 0
; TB_ADDBUTTONS メッセージを送信
pm = hTool, 0x0414
pm.2 = 1 ; 追加するボタンの数(1個)
getptr pm.3, tbb ; TBBUTTON 構造体のアドレス
sendmsg pm
loop
; TB_AUTOSIZE メッセージ送信
pm = hTool, 0x0421, 0, 0
sendmsg pm
; ウィンドウのサブクラス化
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
dialog "コマンドID "+cmdID+" のボタンが押されました"
return
ツールバーのボタンが押されると、押されたボタンのコマンドIDが表示されます。
上のサンプルスクリプト中では問題になっていませんが、ツールバーはHSPウィンドウ上に子ウィンドウとして貼り付けられるものなので、ツールバーの下に描画されている画像は見えなくなります。したがって、ツールバーの高さを取得して、それに合わせてウィンドウを描画していく必要があります。
ツールバーの高さの取得は、ステータスバーの場合と同様に、ツールバー作成後に GetWindowRect 関数でウィンドウの座標を取得し、これから高さを計算するという方法を用います。
pm.0 = hTool ; ツールバーのハンドル getptr pm.1, rect ; 変数 rect (RECT構造体)のアドレス dllproc "GetWindowRect", pm, 2, D_USER nheight = rect.3 - rect.1 ; 高さの取得