今回は、前回作成したタブコントロールの中に描画したり、HSPオブジェクトを乗せてみたりします。こつさえ分かってしまえば楽です。HSPウィンドウに描画するのと同じですから。
さらに、ウィンドウをシステムカラーで塗りつぶしてみたりもします。
タブコントロールの中に描画をするのに、今回はちょっとした裏技的手法を用います。どのような方法かというと、「bgscr で作成したHSPウィンドウをタブコントロールの子ウィンドウとして貼り付ける」というものです。いったんウィンドウを貼り付けてしまえば、あとは通常どおりに描画することができるので、非常に簡単になります。
HSPウィンドウをタブコントロールの子ウィンドウとする実際の手順としては、以下のようになります。
まずはタブコントロールを作成して、タブアイテムも追加しておきます。これは前回行なったことと同じです。
次に、タブコントロール上に子ウィンドウを貼り付ける際に必要となる、タブコントロール上の表示領域の座標を取得する必要があります。この座標から、子ウィンドウとなるHSPウィンドウの幅と高さを求めることができます。
表示領域の座標を求めるには、タブコントロールに TCM_ADJUSTRECT メッセージを送信します。
#define TCM_ADJUSTRECT 0x1328 TCM_ADJUSTRECT wParam = fLarger; // 実行する操作 lParam = pRect; // RECT構造体のアドレス
このメッセージは、タブコントロールのサイズから内部の表示領域を求めるので、 fLarger パラメータには 0 (FALSE) を指定します。 pRect パラメータには、タブコントロールのウィンドウサイズを格納した RECT 構造体を指定します。ただし、この構造体が指す左上座標(left メンバと top メンバ)には 0 を、右下座標(right メンバと bottom メンバ)にはコントロールのサイズを格納しておかなければなりません。
この際に必要となるタブコントロールのサイズを取得するには、ウィンドウのクライアント座標を取得する GetClientRect 関数を使うのが便利です。
BOOL GetClientRect( HWND hWnd, // ウィンドウハンドル PRECT pRect // RECT構造体へのポインタ );
GetClientRect 関数の第2引数(pRect パラメータ)で指定される RECT 構造体にはタブコントロールのクライアント座標(左上座標が 0 になる)が格納されるので、この構造体をそのまま TCM_ADJUSTRECT メッセージのパラメータに指定することができます。タブコントロールには非クライアント領域がなく、ウィンドウサイズとクライアント領域サイズが等しいので、これで問題ありません。
TCM_ADJUSTRECT メッセージを送って取得した RECT 構造体には、ウィンドウの左上および右下の座標がそれぞれ格納されているので、右下x座標(right メンバ)から左上x座標(left メンバ)を引いて幅を求め、同様に右下y座標(bottom メンバ)から左上y座標(top メンバ)を引いて高さを求めることができます。
次に、 bgscr 命令でHSPウィンドウを作成します。このとき、ウィンドウの幅と高さは、先ほど取得したコントロールの表示領域から幅と高さを求めて、その値を指定します。また、ウィンドウは非表示の状態になっている必要があるので、 bgscr 命令実行時に非表示のオプションを指定するか、ウィンドウ作成後に gsel でウィンドウをいったん非表示にしておく必要があります。ここでいったん非表示にしておかないと、後でタスクバー上にボタンが残ったままになってしまいます。
HSPウィンドウは作成された状態で子ウィンドウスタイルを持っていないので、ウィンドウスタイルを変更する必要があります。
スタイルの変更を行なうには、まず GetWindowLong 関数を呼び出して、現在のウィンドウスタイルを取得します。
取得したスタイルから、 WS_POPUP (0x80000000) を取り除き、 WS_CHILD (0x40000000) を付加します。 WS_CHILD スタイルは、ウィンドウが子ウィンドウであることを示すスタイルです。 WS_POPUP スタイルを取り除くのは、 WS_POPUP と WS_CHILD は同時に指定することができないためです。 WS_POPUP を取り除くには、元のスタイルに 0x7FFFFFFF をAND結合すればできます。
こうして修正された新しいスタイルを、 SetWindowLong 関数を呼び出してHSPウィンドウに設定します。
GetWindowLong 関数や SetWindowLong 関数は、LLMODモジュールで定義されている setwndlong 命令を使って呼び出すことができます。
ウィンドウスタイルの変更ができたら、 SetParent 関数を呼び出し、タブコントロールを親ウィンドウにしてしまいます。
HWND SetParent( HWND hwndChild, // 子ウィンドウのハンドル HWND hwndNewParent // 新しい親ウィンドウのハンドル );
第1引数(hwndChild パラメータ)にHSPウィンドウのハンドルを BMSCR 構造体から取得して指定し、第2引数(hwndNewParent パラメータ)にタブコントロールのハンドルを指定します。
これでHSPウィンドウがタブコントロールの子ウィンドウになったので、ウィンドウはタブコントロール上に表示されますが、このままでは正しい位置に表示されません。実際に表示させるべき位置に移動させる必要があります。
はじめに TCM_ADJUSTRECT メッセージを使ってコントロールの表示領域を求めているので、その領域に移動させます。このとき、 width 命令ではうまく設定することができないので、 MoveWindow 関数を使ってウィンドウ位置を設定します。
BOOL MoveWindow( HWND hWnd, // ウィンドウハンドル int x, // x座標 int y, // y座標 int nWitdh, // 幅 int nHeight, // 高さ BOOL bRepaint // 再描画フラグ );
最後の引数(bRepaint パラメータ)は、再描画フラグです。 1 (TRUE) を指定すると、直ちに再描画を行ないます。ウィンドウが非表示の状態で移動する場合には、再描画をする必要はありません。
以上の操作で、ウィンドウをタブコントロール上に貼り付けることができました。あとは貼り付けてあるウィンドウ上にいつもどおりの方法で描画をして、最初に非表示にしたのを再び gsel で表示すれば、タブコントロール上に表示されるはずです。タブコントロール上に貼り付けたウィンドウのサイズ変更されてしまうかもしれませんが、これはシステム変数 winx, winy から得ることができます。
ところで、たいていの場合はタブコントロールに複数のページを作成すると思います。別のページが選択されて TCN_SELCHANGE メッセージが送られてきたときに、一度画面を消去してからもう一度描画しなおすのもいいですが、せっかく bgscr 命令でウィンドウをたくさん作成することができるのですから、各ページで1個ずつウィンドウを割り当ててしまうと良いでしょう。複数のウィンドウをタブコントロール上に貼り付けておいて、 TCN_SELCHANGE メッセージが送られてきたら、今までのウィンドウを非表示にして、選択されたタブに割り当てたウィンドウを表示すれば良いのです。表示・非表示の切り替えは gsel 命令で行なうことができます。
タブコントロール上に貼り付けたウィンドウやタブコントロールの親ウィンドウの背景が白色のままというのはちょっと違和感がありますね。ついでなのでもう1つ、ウィンドウをシステムカラーで塗りつぶしてしまいましょう。
Windowsのシステムカラーは、 GetSysColor 関数で簡単に取得することができます。
DWORD GetSysColor( int nIndex // システムカラーのインデックス );
引数(nIndex パラメータ)には通常は 15 (COLOR_BTNFACE) を指定すれば良いでしょう。この関数を呼び出すと、戻り値として取得した色のCORORREF値(RGB値)が返ります。この値は、赤の輝度を 0xRR、緑の輝度を 0xGG、青の輝度を 0xBB としたとき、 0x00BBGGRR で表されます。これを各色の輝度に分けて取得するには以下のようにすれば良いです。
rgb = (RGB値) r = rgb & 0xFF ; 赤の輝度 g = (rgb >> 8 ) & 0xFF ; 緑の輝度 b = (rgb >> 16) & 0xFF ; 青の輝度
あとは、この値を color 命令で指定してから boxf で塗りつぶせばOKですね。
ただし、ウィンドウがパレットモードで初期化されている場合は、取得したシステムカラーをパレットに含ませる必要があります。
ところで、ディスプレイがフルカラー表示(24ビット以上)でない場合には、上記の方法で描画された部分がタブコントロールやほかのウィンドウの色とは微妙に異なってしまう場合があります。完全に正しく表示されるには、ディスプレイがフルカラー表示でなければなりません。
さて、実際にスクリプトを書いてみます。
#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 ;=============================================================== ; GetTabPos タブコントロールの描画位置とサイズ取得 ;=============================================================== #deffunc GetTabPos val, int mref ret, 16 ; 座標とサイズを格納する変数 mref hTab, 1 ; タブコントロールのハンドル ; クライアント座標取得 pm = hTab getptr pm.1, ret dllproc "GetClientRect", pm, 2, D_USER@ ; 表示領域の座標に変換 ; TCM_ADJUSTRECT メッセージ送信 pm = hTab, 0x1328, 0 getptr pm.3, ret sendmsg pm ; 幅・高さを求める ret.2 -= ret.0 ret.3 -= ret.1 return ;=============================================================== ; SetTabChild タブコントロールに描画中HSPウィンドウを貼り付け ;=============================================================== #deffunc SetTabChild int, int mref hTab, 0 ; タブコントロールのハンドル mref bmscr, 67 ; 描画中ウィンドウのBMSCR構造体 ; ウィンドウスタイル取得 pm = bmscr.13, -16 setwndlong pm, 1 style = stat ; WS_POPUP (0x80000000) 削除, WS_CHILD (0x40000000) 付加 style = style & 0x7FFFFFFF | 0x40000000 ; ウィンドウスタイル設定 pm = bmscr.13, -16, style setwndlong pm ; 親ウィンドウの設定 pm = bmscr.13, hTab dllproc "SetParent", pm, 2, D_USER@ ; 表示領域を求める GetTabPos rect, hTab ; ウィンドウを移動 pm = bmscr.13, rect.0, rect.1, rect.2, rect.3, 0 dllproc "MoveWindow", pm, 6, D_USER@ return #global ;############# モジュール終わり ######################## #module ;######### システムカラー取得モジュール ################ ;=============================================================== ; SystemColor カレントカラーをシステムカラーに設定 ;=============================================================== #deffunc SystemColor int mref index, 0 ; システムカラーのインデックス ; システムカラーを取得 pm = index dllproc "GetSysColor", pm, 1, D_USER@ clr = stat & $FF, (stat>>8) & $FF, (stat>>16) & $FF ; カレントカラーをシステムカラーに設定 palette 137+index, clr.0, clr.1, clr.2 : palfade color clr.0, clr.1, clr.2 return #global ;############# モジュール終わり ######################## #define WM_NOTIFY 0x004E ; 負の数は10進数で #define 定義できないので16進形式で定義 ; (#define TCN_SELCHANGE -551) #define TCN_SELCHANGE 0xFFFFFDD9 screen 0, 250, 200, 2 ; 非表示で作成 ; システムカラーで塗りつぶす SystemColor 15 boxf objsize 90 pos 50, 170 : button "OK", *lb_ok pos 150, 170 : button "キャンセル", *lb_cansel ; タブコントロールの作成 CreateTabCtl 10, 10, 230, 150 hTab = stat ; コントロールのハンドル ; タブアイテム(ページ)の追加 AddTabItem hTab, "タブ1", 0 AddTabItem hTab, "タブ2", 1 AddTabItem hTab, "タブ3", 2 ; タブコントロールの位置・サイズを取得 GetTabPos tabpos, hTab ; 1ページ目タブの子ウィンドウ bgscr 2, tabpos.2, tabpos.3, 2 ; 非表示で作成 SetTabChild hTab ; タブコントロール上に貼り付ける SystemColor 15 : boxf ; システムカラーで塗りつぶし pos 10, 10 : color 0,0,0 : objsize 150 mes "ページ1" mes "描画領域サイズは "+winx+", "+winy chkbox "チェックボックス", chk mes "コンボボックス" combox cb,, "アイテム0\nアイテム1\nアイテム2" ; 2ページ目タブの子ウィンドウ bgscr 3, tabpos.2, tabpos.3, 2 ; 非表示で作成 SetTabChild hTab ; タブコントロール上に貼り付ける SystemColor 15 : boxf ; システムカラーで塗りつぶし pos 10, 10 : color 0,0,0 mes "ページ2" mes "エディットボックス" sdim buf, 1024 mesbox, buf, winx-20, 60, 1 ; 3ページ目タブの子ウィンドウ bgscr 4, tabpos.2, tabpos.3, 2 ; 非表示で作成 SetTabChild hTab ; タブコントロール上に貼り付ける SystemColor 15 : boxf ; システムカラーで塗りつぶし pos 10, 10 : color 0,0,0 : objsize 150 mes "ページ3" button "ボタン1", *lb_btn1 button "ボタン2", *lb_btn2 ; 現在の選択タブのウィンドウID widNow = 2 gsel widNow, 1 ; ウィンドウのサブクラス化 gsel 0, 1 ; ウィンドウを表示 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通知が送られたとき gsel widNow, -1 ; 今までのウィンドウを非表示に ; 選択されたタブアイテムを取得 GetTabSel hTab if stat == 0 : widNow = 2 if stat == 1 : widNow = 3 if stat == 2 : widNow = 4 gsel widNow, 1 ; 新しいウィンドウを表示 gsel 0 } return *lb_btn1 dialog "ボタン1が押されました" goto *mainloop *lb_btn2 dialog "ボタン2が押されました" goto *mainloop *lb_cansel dialog "キャンセルされました" end *lb_ok ; 結果の表示 if chk { t = "チェックされました" } else { t = "チェックされませんでした" } dialog t, 0, "チェックボックス" dialog "「アイテム"+cb+"」が選択されました", 0, "コンボボックス" dialog buf, 0, "エディットボックス" end