今回作成するのはコモンコントロールの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標準の電卓で簡単に求められます。(「電卓の種類」メニューで『関数電卓』を選択)
次回は、ちょっとした裏技的手法によりタブコントロールの中に描画をしてみたいと思います。