
今回作成するのはコモンコントロールの1つ『タブコントロール』です。このコントロールは複数のページをウィンドウに表示することができるようにするものです。ユーザーがタブを選択すると、それぞれのページの情報が表示されるようにします。
今回は、右のようなものを作成します。タブコントロールの中の表示領域に描画はしません。タブコントロールを作成して、それぞれのタブが選択されたら、通知メッセージを受け取ってその旨をメッセージで表示するようにするだけです。
タブコントロールの作成手順は以下のようになります。
タブコントロールの作成は CreateWindowEx 関数で行ないます。ウィンドウクラス名を "SysTabControl32" にすることでタブコントロールが作成できます。ウィンドウスタイルに WS_VISIBLE (0x10000000) と WS_CHILD (0x40000000) を指定するのは他のコモンコントロールと同じですが、ここではさらに WS_CLIPCHILDREN (0x02000000) も合わせて指定しておきます。このスタイルは、ウィンドウが子ウィンドウを持つ場合に子ウィンドウが占める領域を除外して描画するというものです。今回はタブコントロール上に子ウィンドウはありませんが、実際にタブコントロール上に描画をするときには子ウィンドウを置くことになるので、ここでも指定しておくことにします。
タブコントロールが作成できたら、新しいページ(タブアイテム)を追加していきます。アイテムを追加するには、 TCITEM 構造体に情報を格納してから TCM_INSERTITEM メッセージをコントロールに送信します。
TCITEM 構造体は以下のように定義されています。
typedef struct tagTCITEM {
UINT mask; // 有効なメンバ
DWORD dwState; // アイテム状態
DWORD dwStateMask; // dwStateの有効ビットを示すマスク
LPTSTR pszText; // タブの文字列
int cchTextMax; // pszTextのサイズ
int iImage; // イメージインデックス
LPARAM lParam; // アプリケーション定義値
} TCITEM, FAR *LPTCITEM;
mask メンバに 0x0001 (TCIF_TEXT) を指定し、 pszText メンバにはタブに表示する文字列を入れた変数のアドレスを格納しておきます。
TCITEM 構造体に必要な情報を格納したら、タブコントロールに TCM_INSERTITEM メッセージを送信します。
#define TCM_INSERTITEM 0x1307
TCM_INSERTITEM
wParam = iItem;
lParam = pitem;
iImageList パラメータには、新しく挿入するタブアイテムの位置のインデックスを指定します。このインデックスは 0 から始まる値です。 pitem パラメータには、情報を格納しておいた TCITEM 構造体のアドレスを指定します。
以上の操作でタブコントロールは作成できると思います。あとは、ユーザーがタブをクリックなどで選択したときに送られてくるメッセージの取得設定をします。
選択されているタブが変更されると、タブコントロールは親ウィンドウに TCN_SELCHANGE 通知メッセージを送るようになっています。このメッセージは WM_NOTIFY メッセージの形式で送られてきます。
#define TCN_SELCHANGE -551
このメッセージを取得できるように設定するには、以下のようにメッセージ取得設定を行ないます。
set_subclass ; ウィンドウサブクラス化 set_notify -551 ; 通知メッセージ設定
あとは、ループ中でメッセージが送られてくるのを待つのみです。
コントロールから TCN_SELCHANGE 通知メッセージが送られると、 get_message を実行したときに変数 msgval には以下のように代入されることになります。
通知メッセージの中には選択されたアイテムについての情報が含まれていないので、どのタブアイテムが選択されたのかを自分で取得する必要があります。選択されているアイテムを取得するには、タブコントロールに TCM_GETCURSEL メッセージを送信します。
#define TCM_GETCURSEL 0x130B
TCM_GETCURSEL
wParam = 0;
lParam = 0;
このメッセージを送信すると、 SendMessage 関数の戻り値として選択されているアイテムの位置のインデックスが返ります。
さて、実際にスクリプトを書いてみます。
#include "llmod.as"
#include "hsgetmsg.as"
#module ;######## タブコントロール操作モジュール ###############
;===============================================================
; CreateTabCtl タブコントロール作成
;===============================================================
#deffunc CreateTabCtl int, int, int, int
mref cx, 0 ; x座標
mref cy, 1 ; y座標
mref sx, 2 ; 幅
mref sy, 3 ; 高さ
mref stt, 64 ; stat
mref bmscr, 67 ; 描画中ウィンドウのBMSCR構造体
; コモンコントロールライブラリ初期化
dllproc "InitCommonControls", pm, 0, D_COMCTL@
; タブコントロールの作成
pm.0 = cx, cy, sx, sy ; 座標、サイズ
pm.4 = 0x52000000 ; WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS
pm.5 = 0 ; 親ウィンドウ(0のとき描画中ウィンドウ)
pm.6 = 0 ; 拡張ウィンドウスタイル
_makewnd pm, "SysTabControl32"
stt = pm ; タブコントロールのハンドル
return
;===============================================================
; AddTabItem タブアイテム追加
;===============================================================
#deffunc AddTabItem int, str, int
mref hTab, 0 ; タブコントロールのハンドル
mref setText, 33 ; 表示する文字列
mref idx, 2 ; インデックス
sdim szText, 256
szText = setText ; いったん別の変数に移しておく
; TCITEM 構造体
tcitem.0 = 0x0001 ; TCIF_TEXT
getptr tcitem.3, szText
; TCM_INSERTITEM メッセージ送信
pm = hTab, 0x1307, idx
getptr pm.3, tcitem
sendmsg pm
return
;===============================================================
; GetTabSel 選択タブアイテム取得
;===============================================================
#deffunc GetTabSel int
mref hTab, 0 ; タブコントロールのハンドル
; TCM_GETCURSEL メッセージ送信
pm = hTab, 0x130B, 0, 0
sendmsg pm
return
#global ;############# モジュール終わり ########################
#define WM_NOTIFY 0x004E
; 負の数は10進数で #define 定義できないので16進形式で定義
; (#define TCN_SELCHANGE -551)
#define TCN_SELCHANGE 0xFFFFFDD9
; タブコントロールの作成
screen 0, 250, 200
CreateTabCtl 0, 0, winx, winy
hTab = stat ; コントロールのハンドル
; タブアイテム(ページ)の追加
AddTabItem hTab, "タブ1", 0
AddTabItem hTab, "タブ2", 1
AddTabItem hTab, "タブ3", 2
; ウィンドウのサブクラス化
set_subclass ; サブクラス化
set_notify TCN_SELCHANGE ; WM_NOTIFY 形式通知の取得設定
; メッセージパラメータ用変数
dup msg, msgval.1 ; メッセージが格納される変数
dup wprm, msgval.2 ; wParamパラメータが格納される変数
dup lprm, msgval.3 ; lParamパラメータが格納される変数
dup nmhdr, msgval.4 ; NMHDR 構造体が格納される変数
*mainloop
get_message msgval
if msgval {
if (msg == WM_NOTIFY) & (nmhdr == hTab) : gosub *onTabNotify
} else {
wait 10
}
goto *mainloop
*onTabNotify
;--------------- タブコントロールからの WM_NOTIFY ---------------
if nmhdr.2 == TCN_SELCHANGE {
; TCN_SELCHANGE通知が送られたとき
GetTabSel hTab
idx = stat + 1
dialog "タブ"+idx+"が選択されました。"
}
return
スクリプトを実行させると、タブを選択したときにメッセージが表示されますね。
ところで、上のスクリプトを見て気付いたかもしれませんが、HSPでは #define で負の数に定数名を定義させることができません。(少なくとも HSP Ver 2.55 では。) そこで、負の数に定数名を付けるテクニックとして、16進数で定義するというものがあります。例えば、 TCN_SELCHANGE 通知メッセージはコードが -551 (16進数では0xFFFFFDD9)であるので、これを #define で定義するには
#define TCN_SELCHANGE 0xFFFFFDD9
とすればよいのです。16進数はWindows標準の電卓で簡単に求められます。(「電卓の種類」メニューで『関数電卓』を選択)
次回は、ちょっとした裏技的手法によりタブコントロールの中に描画をしてみたいと思います。