HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2017
1109
吹雪TABきーが正しく働くタブコントロールの作り方4解決


吹雪

リンク

2017/11/9(Thu) 21:30:43|NO.81812

先日のラジオボタンに引き続き、今度はタブコントロールの作成を考えています。


http://chokuto.ifdef.jp/urawaza/tabctl1.html
http://chokuto.ifdef.jp/urawaza/tabctl2.html
を参考にすると、bgscrで作ったウィンドウを張り付ける方法が紹介されていますが、この方法で作成を行うと、タブを切り替える部分とその中身が別ウィンドウとなり、TABキーによる移動が正しく行われません。

そこで、先日ラジオボタンの時(http://hsp.tv/play/pforum.php?mode=all&num=81016)でお教えいただいたように、自力でメッセージ処理する方法も検討しました。
 ・各オブジェクトへのWS_TABSTOPの設定
 ・GetMessageその他によるメッセージ処理
を行ってみましたが、やはりうまくいきません。

http://yamatyuu.net/computer/program/sdk/common_control/tabctl2/index.html
を読んで、タブコントロールの中にウィンドウを張り付けるという方法そのものはありではないかと思っています。



 もちろん、タブコントロールを中身のない大きさで配置し、同じウィンドウで中身を描画すればよいという方法で実装可能だろうという事は認識しています。しかし、そのような方法ではコーディングやタブ切り替え時の描画にかかるリソースがとても大きくなるため、可能であれば避けたいと考えています。(特に、キーボード操作でいくつか先のタブに切り替えようとすると、途中の各ページを描画しようとしてしまうために操作がもたつく可能性が高いです。)



 また、TABコントロールではCtrl+Tabでのページ切り替えが一般的に利用可能なはずですが、タブの切り替えのところにマウスでカーソルを入れた状態でさえうまくいきません。これについてはどうしてもの場合はgetkey命令などでキー操作を捕まえれば実現可能とは思いますが、やはり邪道と言わざるを得ません。(TCN_KEYDOWN メッセージの利用も考えられるかとは思っていますが、まだ実験していません。)




 以上2点について、何か良い方法をご存知の方がいらっしゃいましたら、お教えいただければと思います。

 以下に一応私が実験しているソースを掲載しますが、長いのでわざわざお読みいただかなくても大丈夫です。

#module mod_tabControal #uselib "USER32" #func GetClientRect "GetClientRect" sptr,sptr #func GetWindowLong "GetWindowLongA" sptr,sptr #func SetWindowLong "SetWindowLongA" sptr,sptr,sptr #func SetParent "SetParent" sptr,sptr #func MoveWindow "MoveWindow" sptr,sptr,sptr,sptr,sptr,sptr #func GetMessageA "GetMessageA" sptr,sptr,sptr,sptr #func IsDialogMessage "IsDialogMessage" sptr,sptr #func TranslateMessage "TranslateMessage" sptr #func DispatchMessageA "DispatchMessageA" sptr #deffunc tabControal array v0,int v1,int v2,int v3 //v0に情報保存用の配列(事前の初期化は不要) //v1,v2 サイズx,y //v3 スタイル地 winobj "SysTabControl32","設定",0,$52001000 | v3,v1,v2 //WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS tmp=stat //配列に情報保存 v0.0=objinfo(tmp,2) //ハンドル v0.1=ginfo_sel //作成先画面ID v0.2=tmp //オブジェクトID v0.3=-2100000000 //終端を示す return tmp #deffunc tabAdd array v0,int v1,int v2,str v3 //v0に情報保存用の配列 //v1=新規作成する画面ID //v2=作成するタブのインデックス //v3=タイトル文字列 if length(v0)<3:return -1 //v0の指定ミス bkup_sel=ginfo_sel dim tmp,7 //PCITEM構造体 tmp2=v3 tmp=1,0,0,varptr(tmp2),0,0,0 //TCIF_TEXTフラグをたてておく。 sendmsg v0,$1307,v2,varptr(tmp) //TCM_INSERTITEMA if stat=-1:return -2 //失敗。成功していれば作ったタブのインデックスが返る tmp2=stat addArray@mod_tabControal v0,stat,v1 //配列v0にウィンドウ情報を保存 dim tmp,4 GetClientRect v0,varptr(tmp) //タブコントロールのサイズ取得 if stat=0:return -3 //失敗 sendmsg v0,$1328,0,varptr(tmp) //TCM_ADJUSTRECT bgscr v1,tmp.2-tmp.0,tmp.3-tmp.1,2 //非表示でウィンドウ作成 getWindowLong hwnd,-16 //GWL_STYLE setWindowLong hwnd,-16,stat & $7FFFFFFF | $40000000 //WS_POPUP (0x80000000) 削除, WS_CHILD (0x40000000) 付加 SetParent hwnd,v0 //オーナー設定 MoveWindow hwnd,tmp.0,tmp.1,tmp.2-tmp.0,tmp.3-tmp.1,0 //最後の0は再描画フラグ if tmp2=tabGet(v0,1):gsel v1,1 //現在表示中のタブだったら、表示する gsel bkup_sel,0 //元に戻しておく return tmp2 #defcfunc tabGet array v0,int v1 //情報取得 //v0=情報保存配列(またはハンドル) //v1=取得情報のタイプ if v1<0 or v1>3:return -1 if v1=0:{ //タブの数 sendmsg v0,$1304,0,0 //TCM_GETITEMCOUNT return stat //失敗時は0 } if v1=1:{ //現在選択中のタブのインデックス sendmsg v0,$130B,0,0 //TCM_GETCURSEL return stat } if v1=2:{ //フォーカスを持つタブのインデックス。選択中のタブと異なる場合があるらしい。 sendmsg v0,$132F,0,0 //TCM_GETCURFOCUS return stat } if v1=3:{ //タブの行数 sendmsg v0,$132C,0,0 //TCM_GETROWCOUNT return stat } return -1 #deffunc local addArray array v0,int v1,int v2 //管理する配列に情報追加 //とりあえずは追加先インデックスは最終と仮定 tmp=3 repeat if v0.tmp=-2100000000:break tmp++ loop v0.tmp=v1 v0.(tmp+1)=v2 v0.(tmp+2)=-2100000000 return #deffunc tabSelChange array v0,int v1 //WM_NOTIFYでTCN_SELCHANGEを受信時に呼ぶ事! //v0には情報保存用の配列、v1にはlparamを指定する //思い当たる配列をv0に入れてこの命令を呼び、正しく処理されれば0が返る。 //-1になったら指定する配列が間違っているという事。呼び出し側では、これを確認して可能性のあるものを試せばよい dupptr NMHDR,v1,12 //NMHDR構造体 if NMHDR.2!=$FFFFFDD9:{ //エラー処理 //ここではreturn命令にパラメータ指定できないので注意。 //statに値を返す場合はmrefの使用が必須 mref ret,64 ret=-2 return //TCN_SELCHANGE でない } if NMHDR.0!=v0:{ //指定した構造体が間違っている mref ret,64 ret=-1 return } if length(v0)<3:{ // 〃 mref ret,64 ret=-1 return } bkup_sel=ginfo_sel tmp=3 repeat if v0.tmp=-2100000000:break //終端に到達 if tmp\2=0:gsel v0.tmp,-1 //タブに関連する画面を全て非表示にする //将来的にはTCN_SELCHANGINGでやるべき tmp++ loop gsel v0.(tabGet(v0,1)*2+4),1 //新たに選択されたタブの画面を表示 gsel bkup_sel //戻しておく mref ret,64 //statの値 ret=0 return #deffunc setTabstop int p1 //p1で指定したIDのオブジェクトにWS_TABSTOPを設定 GetWindowLong objinfo(p1,2),-16 setWindowLong objinfo(p1,2),-16,stat | $10000 //WS_TABSTOP return #deffunc Check //メインループ内で呼んでもらう。キー操作の受付のため必要。 await 1 GetMessageA varptr(msg),0,0,0 if stat=-1 | stat=0:return IsDialogMessage hwnd,varptr(msg) if stat:return TranslateMessage varptr(msg) DispatchMessageA varptr(msg) return #global //サンプル #if 1 cls 4 oncmd gosub *notify,$4E //WM_NOTIFY pos 100,10 tabControal tab,300,100,0 settabstop stat tabadd tab,100,0,"ページ1" tabadd tab,101,1,"ページ2" gsel 100 font msgothic,60 in1="1ページ目の入力欄" input in1,150 settabstop stat input in1,150 settabstop stat gsel 101 font msgothic,60 in2="2ページ目の入力欄" input in2,150 settabstop stat gsel 0 repeat Check wait 1 loop *notify dupptr NMHDR,lparam,12 //NMHDR構造体 if NMHDR.2=$FFFFFDD9:{ //TCN_SELCHANGE tabSelChange tab,lparam // dialog stat,0,"処理結果" } return #endif



この記事に返信する


いののて

リンク

2017/11/11(Sat) 12:05:58|NO.81815

タブ項目のウィンドウの拡張スタイルにWS_EX_CONTROLPARENTを追加し、
そのウィンドウの親をタブコントロールではなく、
HSPウィンドウに設定するとTABでフォーカスをあわせることができるようになります。



吹雪

リンク

2017/11/11(Sat) 18:21:43|NO.81818

>> いののて 様

 回答ありがとうございます。
 ウィンドウ位置の調整が少々面倒でしたが、無事TABキーでの移動が出来ました。



 残る課題であるCtrl+TABについては、やはりどうしようもならないのでしょうか。



いののて

リンク

2017/11/12(Sun) 19:54:54|NO.81831

いろいろ実験してみたところ、コモンコントロールのプロパティシート(ファイルのプロパティとかのダイアログ)
のみにしか、Ctrl+TABは働かないようです。
IsDialogMessageを使用したメッセージループを使っても、実行ファイルのリソース内のダイアログを使っても、Ctrl+TABは使えませんでした。



吹雪

リンク

2017/11/12(Sun) 22:49:02|NO.81833

>> いののて 様

 わざわざありがとうございます。
 これについてはあきらめる事にします。

 ありがとうございました。



ONION software Copyright 1997-2023(c) All rights reserved.