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


HSPTV!掲示板


未解決 解決 停止 削除要請

2017
0819
Fubukiキーボードから正しく操作できるラジオボタンの設置15解決


Fubuki

リンク

2017/8/19(Sat) 23:50:45|NO.81016

 様々なサイトのサンプルを見ながら、ラジオボタンを制作しています。
 以下は一例で、他にもbutton命令を使うもの、winobjで作るものなど複数を試しています。
 しかし、他のアプリケーションで見られるもののように、上下矢印キーでの項目選択ができません。
 もちろん、キー入力を監視して切り替えることはできるのでしょうが、出来れば正攻法で行きたいと思っています。

 うまくキーボード操作できるラジオボタンを鶴久方法をご存知の方、お教えいただけないでしょうか。




pos 10,10 objsize 250,40 chkbox get("delete","Words"),tmp objskip stat,1 h1=objinfo(stat,2) SetWindowLong h1,-16,$50020009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP chkbox get("trash","Words"),tmp2 h2=objinfo(stat,2) SetWindowLong h2,-16,$50000009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON



この記事に返信する


科学太郎

リンク

2017/8/20(Sun) 21:32:50|NO.81027

>様々なサイトのサンプルを見ながら、ラジオボタンを制作しています。
ラジオボタンを使ってるのか?
自作のラジオボタン・コントロールを作ってるのか?
どちら?

>以下は一例で、他にもbutton命令を使うもの、winobjで作るものなど複数を試しています。
>しかし、他のアプリケーションで見られるもののように、上下矢印キーでの項目選択ができません。
グループボックスなどが関係します。
分かりますか?

>もちろん、キー入力を監視して切り替えることはできるのでしょうが、出来れば正攻法で行きたいと思っています。
つまり、普通に BS_AUTORADIOBUTTON スタイルの動作で良いという事だよね。

>うまくキーボード操作できるラジオボタンを鶴久方法をご存知の方、お教えいただけないでしょうか。
ダイアログと同じようなキー操作ですよね。



eoe

リンク

2017/8/20(Sun) 22:23:52|NO.81028

>キー入力を監視して切り替えることはできるのでしょうが
HSPではこっちが正攻法です。
あなた言う正攻法はメッセージループをどうにかしないといけないのでHSPでは難しいです。
無理やり何とかする方法もあるみたいですがそれよりも素直な方法でやった方がいいです。



Fubuki

リンク

2017/8/21(Mon) 00:16:02|NO.81030

>> 科学太郎 様

 コントロールパネルなどでもよくみるラジオボタンを作っています。
 ご指摘の通り、BS_AUTORADIOBUTTONと同じ挙動のものです。

 グループボックスについては、作成方法は知っていますが単なる見かけ上の意味しかないものと認識しています。
 (MSDNにも見た目とアクセスキー設定以上の効果はないとの記述がありましたので・・・)

>> eoe 様

 どうしてもむずかしそうなら、そうしたいと思います。
 ただ、このような方法ではモジュール化も難しく、できれば避けたいと思い質問させていただきました。



 昨日のコードには抜けも多かったので、ご指摘頂いたグループボックスも一応作ったうえでのサンプルを下に張り付けます。
私が分かっているのはここまでです。




#uselib "user32.dll" #func SetWindowLong "SetWindowLongA" sptr,sptr,sptr //グループボックス作成 winobj "BUTTON","グループ",0,$50400107,400,400 //$50400107=WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_GROUPBOX | BS_LEFT //WS_CLIPSIBLINGSの意味は不明だが、サンプルに合ったのでつけておく //ラジオボタン作成 pos 100,100 chkbox "選択肢1",tmp h1=objinfo(stat,2) SetWindowLong h1,-16,$50020009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP chkbox "選択肢2",tmp2 h2=objinfo(stat,2) SetWindowLong h2,-16,$50000009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON stop



eoe

リンク

2017/8/21(Mon) 08:53:03|NO.81040

じゃあそのスクリプトで動かすサンプルを載せます。
でもメッセージループをスクリプトで行うのはいろいろ制約ありそうだし実用性はありません。

#include "user32.as" //グループボックス作成 winobj "BUTTON","グループ",0,$50400107,400,400 //$50400107=WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_GROUPBOX | BS_LEFT //WS_CLIPSIBLINGSの意味は不明だが、サンプルに合ったのでつけておく //ラジオボタン作成 pos 100,100 chkbox "選択肢1",tmp h1=objinfo(stat,2) SetWindowLong h1,-16,$50020009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP chkbox "選択肢2",tmp2 h2=objinfo(stat,2) SetWindowLong h2,-16,$50000009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON SetFocus h1 dim msg,7 repeat GetMessage varptr(msg),0,0,0 if stat==-1 | stat==0:break IsDialogMessage hwnd,varptr(msg) if stat:continue TranslateMessage varptr(msg) DispatchMessage varptr(msg) loop end



MillkeySoftw

リンク

2017/8/21(Mon) 09:01:27|NO.81041

oncmd でメッセージを処理できる。
現在のフォーカスがラジオボタンだった場合で方向キーを押された場合に移行したいラジオボタンにフォーカスを移せば操作できるよね。



科学太郎

リンク

2017/8/21(Mon) 09:44:13|NO.81042

次のソースコードはC言語で「単純なウインドウ」を作成する部分です。

//------------------------------------------------ // メイン関数 //------------------------------------------------ extern int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { LPCTSTR lpClassName = TEXT("XXXX_WndClass"); LPCTSTR lpTitleName = TEXT("キャプション"); MSG Msg; if ( funcWindowClass(hInstance,lpClassName) == 0 ){ return -1; } if ( funcCreateWindow(hInstance,lpClassName,lpTitleName,nCmdShow) == NULL ){ return -2; } while ( GetMessage(&Msg,NULL,0,0) > 0 ){ TranslateMessage( &Msg ); DispatchMessage( &Msg ); } return Msg.wParam; }
次のソースコードもC言語ですが「ダイアログ・ウインドウ」を作成する内容です。

//------------------------------------------------ // メイン関数 //------------------------------------------------ extern int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) { LPCTSTR lpClassName = TEXT("XXXX_WndClass"); HWND hWnd; MSG Msg; if ( funcDialogClass(hInstance,lpClassName) == 0 ){ return -1; } if ( (hWnd = CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG01),NULL,mainDialogProc)) == NULL ){ return -2; } while ( GetMessage(&Msg,NULL,0,0) > 0 ){ if ( !IsDialogMessage(hWnd,&Msg) ){ // ここに注目 TranslateMessage( &Msg ); DispatchMessage( &Msg ); } } return Msg.wParam; }
上記の IsDialogMessage 関数に注目してください。
この1行を入れるとダイアログと同じキー操作になります。

しかし、HSPのウインドウは「単純なウインドウ」として内部で処理されてます。
このような場合は、IsDialogMessage 関数が存在しないために
ダイアログと同じカーソル移動キーの処理は行えません。

ところが objskip 命令の説明を読むと次のようになってます。

通常は、オブジェクトを配置した段階で最適なモードが設定されているので、 フォーカス移動モードを再設定する必要はありません。 特殊な役割を果たすオブジェクトだけ、フォーカス移動モード変えたり、 winobj命令によりシステム定義のオブジェクトを新しく追加した場合に使用してください。
また、objskip 命令のサンプル(calcsheet.hsp)を実行すると[TAB]キーの移動が可能ですね。
簡単なサンプルを作って確認しましたが、WS_TABSTOP スタイルがなくても[TAB]キーで移動できたり、
方向キーの[←]、[↑]、[↓]、[→]キーでは全く移動しません。

このことから HSP は内部で IsDialogMessage 関数と同等(TABのみ)の処理を行ってるようです。
そうなると HSP の内部では WS_TABSTOP、WS_GROUP のスタイルはチェックしていないだろうし、
普通に考えると方向キーの[←]、[↑]、[↓]、[→]キーでは移動不可能です。

eoe さんが、既に解決策を提示しているようですね。

MillkeySoftwさんへ。
> oncmd でメッセージを処理できる。
> 現在のフォーカスがラジオボタンだった場合で方向キーを押された場合に移行したいラジオボタンにフォーカスを移せば操作できるよね。
簡単なサンプルを作ってみましたが、上手く動きませんでしたよ。
oncmd で WM_KEYDOWN メッセージを処理すれば良いかと思ったが、
[TAB]キーを一度も押さなければ方向キーを処理できるが、
[TAB]キーを一度押すと WM_KEYDOWN メッセージで方向キーをキャッチできない。



科学太郎

リンク

2017/8/21(Mon) 09:52:10|NO.81043

追記。

面白いテーマだったのでサンプルを作成してみました。

//------------------------------------------------------------------------------ // ラジオボタンのグループ化(3) by 科学太郎 //============================================================================== // @URL(http://hsp.tv/play/pforum.php?mode=all&num=81016)→「キーボードから正しく操作できるラジオボタンの設置」 //------------------------------------------------------------------------------ #include "User32.as" //-------------------------------------- // 記号定数(API定数) //-------------------------------------- #const global NULL 0 #const global BM_GETCHECK $000000F0 #const global BM_SETCHECK $000000F1 #const global BM_SETSTYLE $000000F4 #const global BS_AUTORADIOBUTTON $00000009 # #const global GWL_STYLE $FFFFFFF0 #const global WS_TABSTOP $00010000 #const global WS_GROUP $00020000 //-------------------------------------- // 列挙定数(オブジェクトID) //-------------------------------------- #enum RID_RADIO10=0 #enum RID_RADIO11 #enum RID_RADIO12 #enum RID_RADIO13 #enum RID_RADIO14 # #enum RID_RADIO20 #enum RID_RADIO21 #enum RID_RADIO22 # #enum RID_RADIO30 #enum RID_RADIO31 #enum RID_RADIO32 #enum RID_RADIO33 # #enum MAX_CONTROL //-------------------------------------- // メイン部 //-------------------------------------- *Init dim Msg,7 ;Msg構造体 nRadio1=0 ;グループ nRadio2=1 ;グループ nRadio3=3 ;グループ *Main screen 0,640,480,SCREEN_NORMAL|SCREEN_FIXEDSIZE syscolor 15:boxf:color:title "ラジオボタンのグループ化(3) by 科学太郎" ;配置(グループ) objsize 200,25 mes "" repeat 5 button gosub strf("グループ Д薀献ボタン(%d)",cnt+10), *RadioButton1 SetGroupTabStop objinfo_hwnd(stat) loop ;配置(グループ) objsize 200,25 mes "" repeat 3 button gosub strf("グループ◆Д薀献ボタン(%d)",cnt+20), *RadioButton2 SetGroupTabStop objinfo_hwnd(stat) loop ;配置(グループ) objsize 200,25 mes "" repeat 4 button gosub strf("グループ:ラジオボタン(%d)",cnt+30), *RadioButton3 SetGroupTabStop objinfo_hwnd(stat) loop ;初期値 SetRadioButton RID_RADIO10,RID_RADIO14,nRadio1 SetRadioButton RID_RADIO20,RID_RADIO22,nRadio2 SetRadioButton RID_RADIO30,RID_RADIO33,nRadio3 ;設定(フォーカス) objsel(RID_RADIO10+nRadio1) repeat ;デバッグ情報 redraw 0 DrawDebug redraw 1 ;メッセージの処理 GetMessage varptr(Msg),NULL,0,0 if(stat==0):break if(stat< 0):break ;ここに注目 IsDialogMessage hWnd,varptr(Msg) if(stat):continue TranslateMessage varptr(Msg) DispatchMessage varptr(Msg) loop end //-------------------------------------- // グループ,料択取得 //-------------------------------------- *RadioButton1 GetRadioButton RID_RADIO10,RID_RADIO14,nRadio1 return //-------------------------------------- // グループ△料択取得 //-------------------------------------- *RadioButton2 GetRadioButton RID_RADIO20,RID_RADIO22,nRadio2 return //-------------------------------------- // グループの選択取得 //-------------------------------------- *RadioButton3 GetRadioButton RID_RADIO30,RID_RADIO33,nRadio3 return //-------------------------------------- // WS_GROUPとWS_TABSTOPを設定 //-------------------------------------- #deffunc SetGroupTabStop int _wnd_ SendMsg(_wnd_),BM_SETSTYLE,BS_AUTORADIOBUTTON,0 if(cnt==0){ GetWindowLong(_wnd_),GWL_STYLE SetWindowLong(_wnd_),GWL_STYLE,stat|WS_GROUP|WS_TABSTOP } return //-------------------------------------- // ラジオボタンの項目番号を設定 //-------------------------------------- #deffunc SetRadioButton int _idFirst_,int _idLast_,int _no_ repeat((_idLast_)-(_idFirst_)+1),(_idFirst_) SendMsg objinfo_hwnd(cnt),BM_SETCHECK,0,0 loop SendMsg objinfo_hwnd(_idFirst_+_no_),BM_SETCHECK,1,0 return //-------------------------------------- // ラジオボタンの項目番号を取得 //-------------------------------------- #deffunc GetRadioButton int _idFirst_,int _idLast_,var _no_ repeat((_idLast_)-(_idFirst_)+1),(_idFirst_) SendMsg objinfo_hwnd(cnt),BM_GETCHECK,0,0 if(stat):_no_=(cnt)-(_idFirst_):break loop return(_no_) //-------------------------------------- // デバッグ用のスタイル監視 //-------------------------------------- #deffunc DrawDebug syscolor 15:boxf:color ;スタイルの監視 pos 200,0 repeat MAX_CONTROL GetWindowLong objinfo_hwnd(cnt),GWL_STYLE if(stat & WS_GROUP):mes "" mes strf("id%02d=$%08X",cnt,stat) loop ;選択変数の監視 pos 400,0 mes "" mes strf("nRadio1=%d",nRadio1) mes strf("nRadio2=%d",nRadio2) mes strf("nRadio3=%d",nRadio3) return //------------------------------------------------------------------------------ // End of sample196c(ラジオボタンのグループ化).hsp //------------------------------------------------------------------------------
SetRadioButton、GetRadioButton命令を使えばラジオボタンの処理は楽になると思います。
また、このサンプルを作成して気づきましたが、BS_AUTORADIOBUTTON スタイルを付けた場合は、
ラジオボタンの WS_TABSTOP スタイルが自動的に移動してるようですね。

これにより、[TAB]キーで次のグループの選択されたラジオボタンに移動可能なのでしょうね。
このサンプルで知りましたよ。
なるほどね。MicroSoft。



Fubuki

リンク

2017/8/21(Mon) 12:17:50|NO.81045

>> 科学太郎 様
>> eoe 様

 わざわざサンプル作成ありがとうございます。
・GetMessage
・TranslateMessage
・DispatchMessage
についてはMSDNを読んでもいまいちよくわかりませんでしたが、いただいたスクリプトで問題なく動きそうです。また勉強します。


 設置するボタン数・グループ数に上限を設ければモジュール化もできるという事も分かりました。

 ・押されたボタンのIDがどこかのシステム変数などに代入さえされればいいんですが・・・
 ・ボタンもCOMCTLのWM_NOTIFYのような形で通知をくれれば・・・
 ・HSPのobjskipがWS_TABSTOPを設定する方式であれば・・・

 と、不運な仕様が重なっていて、これ以上はどうしようもなさそうですね。

 ご回答頂いた皆様、ありがとうございました。



科学太郎

リンク

2017/8/21(Mon) 13:34:24|NO.81046

既に解決してるようですが「ひと言」アドバイスです。

> ・押されたボタンのIDがどこかのシステム変数などに代入さえされればいいんですが・・・
ボタンが押された場合、ジャンプ先のラベル内で「stat」を調べるとボタンID(オブジェクトID)が取得可能です。

> ・ボタンもCOMCTLのWM_NOTIFYのような形で通知をくれれば・・・
ボタンの場合は WM_COMMAND メッセージの BN_xxx で通知が送られてきます。

・ボタン(通知メッセージ)
http://wisdom.sakura.ne.jp/system/winapi/win32/win51.html

//-------------------------------------- // 記号定数(API定数) //-------------------------------------- #const global BN_CLICKED $00000000 #const global BN_PAINT $00000001 #const global BN_HILITE $00000002;BN_PUSHEDと同じ #const global BN_PUSHED $00000002 #const global BN_UNHILITE $00000003;BN_UNPUSHEDと同じ #const global BN_UNPUSHED $00000003 #const global BN_DISABLE $00000004 #const global BN_DBLCLK $00000005;BN_DOUBLECLICKEDと同じ #const global BN_DOUBLECLICKED $00000005 #const global BN_SETFOCUS $00000006 #const global BN_KILLFOCUS $00000007
> ・HSPのobjskipがWS_TABSTOPを設定する方式であれば・・・
同感です。
なぜ、独自に objskip 命令で WS_TABSTOP もどきを設定するのだろうか?
[TAB]キーの移動ルーチンで WS_TABSTOP スタイルを見て移動させれば良いのにね。

> と、不運な仕様が重なっていて、これ以上はどうしようもなさそうですね。
不運ですか?



Fubuki

リンク

2017/8/21(Mon) 22:38:23|NO.81052

>> 科学太郎 様

 基本的な事も分かっておらず、すみません。わざわざありがとうございました。

 おかげさまで、以下のように(多少の処理とメモリの無駄はありますが)無事モジュールにする事が出来ました。。

 今回は大変お世話になりました。ありがとうございました。


//------------------------------------------------------------------------------------- // // ラジオボタン設置・管理モジュール // // V1.00 2017.08.21 //------------------------------------------------------------------------------------- #module mod_radioButton #uselib "user32.dll" #func GetWindowLong "GetWindowLongA" sptr,sptr,sptr #func SetWindowLong "SetWindowLongA" sptr,sptr,sptr #func GetMessageA "GetMessageA" sptr,sptr,sptr,sptr #func IsDialogMessage "IsDialogMessage" sptr,sptr #func TranslateMessage "TranslateMessage" sptr #func DispatchMessageA "DispatchMessageA" sptr #deffunc radio str p1,int p2,int p3 //p1 表示文字列(ANSI) //p2 グループフラグ(各グループ最初のラジオボタンにのみ1を指定 //p3 初期値フラグ(初期値としてONに設定しておく場合に1を指定 if Init=0:radioInit if p2=1:{ if group>4:return -2 //グループ数の上限オーバー group++ count.group=0 } else:{ if count.group>6:return -3 //グループ内ボタン数の上限オーバー count.group++ } button gosub p1,*radioPush ID.group.(count.group)=stat if p2=1:{ SetWindowLong objinfo(stat,2),-16,$50030009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP } else:{ SetWindowLong objinfo(stat,2),-16,$50000009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON } if p3=1:setRadioState group,count return ID.group.(count.group) #deffunc radioInit //必要な変数の確保など //基本的には設置時に自動で実行されるが、手動でも実行可能 group=-1 //現在作成中のグループ番号 dim count,5 //各グループ内で最後に作成したアイテム番号 dim sel,5 repeat 5 count.cnt=-1 //初期値は-1にしておく。 sel.cnt=-1 loop dim ID,5,7 //最大5グループ、各グループ7個まで dim msg,7 init=1 return #deffunc radioUnInit //画面クリアの際に呼ぶ事で、これまでのボタンの情報をリセット //多少はメモリの節約になる dim count,1 dim ID,1 dim sel,1 dim msg,1 init=0 return *radioPush tmp=stat repeat 5 if tmp=ID.cnt.0:sel.cnt=0:break if tmp=ID.cnt.1:sel.cnt=1:break if tmp=ID.cnt.2:sel.cnt=2:break if tmp=ID.cnt.3:sel.cnt=3:break if tmp=ID.cnt.4:sel.cnt=4:break if tmp=ID.cnt.5:sel.cnt=5:break if tmp=ID.cnt.6:sel.cnt=6:break loop return #deffunc radioCheck //メインループ内で呼んでもらう。キー操作の受付のため必要。 if init=0:return 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 #defcfunc getRadioState int p1 //現在選択されている項目のインデックスを取得 //p1 グループ番号 if init=0:return -1 //初期化前 if p1<0:return -2 //グループ番号が無効 if p1>5:return -2 //グループ番号が無効 return sel.p1 #deffunc setRadioState int p1,int p2 //選択状態の変更 //p1 グループ番号 //p2 変更後選択項目のインデックス if init=0:return -1 //初期化前 if p1<0:return -2 //グループ番号が無効 if p1>5:return -2 //グループ番号が無効 if sel.p1!=-1:sendmsg objinfo(ID.p1.(sel.p1),2),$F1,0,0 //BM_SETCHECKでチェックを入れる sendmsg objinfo(ID.p1.p2,2),$F1,1,0 //BM_SETCHECKでチェックを入れる sel.p1=p2 return #deffunc setTabstop int p1 //p1で指定したIDのオブジェクトにWS_TABSTOPを設定 //これを入れないと、ラジオボタン以外にTABキーでフォーカスされない GetWindowLong objinfo(p1,2),-16,0 setWindowLong objinfo(p1,2),-16,stat | $10000 //WS_TABSTOP return #global //*************** Sumple *************** font "",32 objmode 2 pos 50,50 winobj "BUTTON","グループ",0,$50400107,250,400 //$50400107=WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_GROUPBOX | BS_LEFT //WS_CLIPSIBLINGSの意味は不明だが、サンプルに合ったのでつけておく pos 70,90 objsize 200,40 radio "ラジオ0",1,0 radio "ラジオ1",0,0 radio "ラジオ2",0,1 radio "ラジオ3",0,0 radio "ラジオ4",0,0 pos 350,50 winobj "BUTTON","グループ",0,$50400107,250,400 pos 370,90 radio "ラジオ0",1,0 radio "ラジオ1",0,0 radio "ラジオ2",0,0 radio "ラジオ3",0,0 radio "ラジオ4",0,0 //背景色設定・グループ名のフォント変更 省略 mes "" button gosub "check",*check setTabstop stat repeat wait 1 radioCheck getkey key,13 if key:gosub *check loop *check if getRadiostate(1)=-1:return if getRadiostate(1)=-1:return dialog getRadiostate(0) dialog getRadiostate(1) return



科学太郎

リンク

2017/8/22(Tue) 00:40:31|NO.81055

> おかげさまで、以下のように(多少の処理とメモリの無駄はありますが)無事モジュールにする事が出来ました。。
良かったですね。

提示されたモジュールの「ちょっと気になった点」を紹介します。

●1つ目
モジュール内の if-else 構文でブロックを使うのならば、マルチステートメントのコロンは不要です。

if p2=1:{ if group>4:return -2 //グループ数の上限オーバー group++ count.group=0 } else:{ if count.group>6:return -3 //グループ内ボタン数の上限オーバー count.group++ }


if p2=1{ if group>4:return -2 //グループ数の上限オーバー group++ count.group=0 }else{ if count.group>6:return -3 //グループ内ボタン数の上限オーバー count.group++ }

●2つ目
モジュールの「setTabstop」命令に引数のバグがあります。

×GetWindowLong objinfo(p1,2),-16,0 ↓ ○GetWindowLong objinfo(p1,2),-16
GetWindowLong 関数は2つの引数のみで第3引数はありません。

●3つ目
どこかで探してきた次のサンプルには間違いが含まれてます。

winobj "BUTTON","グループ",0,$50400107,250,400 //$50400107=WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_GROUPBOX | BS_LEFT //WS_CLIPSIBLINGSの意味は不明だが、サンプルに合ったのでつけておく

ここの「$50400107」は「$54000107」です。

#const global WS_DLGFRAME $00400000 #const global WS_CLIPSIBLINGS $04000000
また、WS_CLIPSIBLINGS スタイルは、親ウインドウが再描画するときに
子ウインドウ(ボタンなど)の矩形を再描画しないようにします。
これにより、ボタンなどの子ウインドウが再描画でちらつかなくなります。

・ウィンドウ スタイル
https://msdn.microsoft.com/ja-jp/library/czada357.aspx

●4つ目
一番下のサンプルで repeat 内で「wait 1」を入れてますが必要ありません。

repeat wait 1 ;不要 radioCheck getkey key,13 if key:gosub *check loop
理由は radioCheck 命令内で GetMessage 関数を呼び出してるからです。
この関数そのものが wait 命令と同じでメッセージがキューに入るまで一時停止してます。

つまり、サンプルの repeat 内は「radioCheck」で停止状態にあり、
キー入力などのイベントが発生すると GetMessage 関数から抜け出ます。


repeat radioCheck ;戻り値を返すように改良!! if(stat):break ;戻り値で break する getkey key,13 if key:gosub *check loop ;ここに onexit と同じ終了処理を書けます。 dialog "ここに onexit と同じ終了処理を書けます。",0,"確認" end
この方法だと HSP の onexit で設定したラベルにはジャンプしないで終了します。
そのために repeat-loop 構文を抜けた後に同じ「終了処理」を書けます。

なお、HSP の onexit で設定したラベルにジャンプさせたい場合は、
wait 命令か await 命令を入れえる必要がありますね。

どちらが良いかは、モジュールを使う側の自由とするために
radioCheck 命令は戻り値を返すようにしておきます。

この戻り値を見て break した場合は onexit のラベルにジャンプしないが、
戻り値を読み捨てて wait 命令などを挿入すれば onexit のラベルにジャンプする仕様です。

#deffunc radioCheck //メインループ内で呼んでもらう。キー操作の受付のため必要。 if(init==0):return 0 GetMessage varptr(msg),0,0,0 if(stat==-1)or(stat==0):return 1 IsDialogMessage hwnd,varptr(msg) if(stat):return 0 TranslateMessage varptr(msg) DispatchMessage varptr(msg) return 0
なお、HSP の onexit のラベルにジャンプ可能な仕様であれば、
radioCheck 命令の方に await などを記述すれば良いのです。

#deffunc radioCheck //メインループ内で呼んでもらう。キー操作の受付のため必要。 if(init==0):return await ;追加(引数なし) GetMessage varptr(msg),0,0,0 if(stat==-1)or(stat==0):return IsDialogMessage hwnd,varptr(msg) if(stat):return TranslateMessage varptr(msg) DispatchMessage varptr(msg) return
これならば

repeat radioCheck getkey key,13 if(key):gosub *check loop
このようにできますね。

●最後に「ちょっと修正した」バージョン(V1.01)を載せておきます。

//------------------------------------------------------------------------------------- // // ラジオボタン設置・管理モジュール // // V1.00 2017.08.21 // V1.01 2017.08.22 //------------------------------------------------------------------------------------- #include "User32.as" #ifndef __INCLUDE_MODRADIOBUTTON__ #define __INCLUDE_MODRADIOBUTTON__ #module mod_radioButton #deffunc radio str p1,int p2,int p3 //p1 表示文字列(ANSI) //p2 グループフラグ(各グループ最初のラジオボタンにのみ1を指定 //p3 初期値フラグ(初期値としてONに設定しておく場合に1を指定 if(Init==0):radioInit if(p2==1){ if(group>=5):return -2 //グループ数の上限オーバー group++ count.group=0 }else{ if(count.group>=7):return -3 //グループ内ボタン数の上限オーバー count.group++ } button gosub p1,*radioPush ID.group.(count.group)=stat if(p2==1){ SetWindowLong objinfo_hwnd(stat),-16,$50030009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP }else{ SetWindowLong objinfo_hwnd(stat),-16,$50000009 //WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON } if(p3==1):setRadioState group,count return ID.group.(count.group) #deffunc radioInit //必要な変数の確保など //基本的には設置時に自動で実行されるが、手動でも実行可能 group=-1 //現在作成中のグループ番号 dim count,5 //各グループ内で最後に作成したアイテム番号 dim sel,5 repeat 5 count.cnt=-1 //初期値は-1にしておく。 sel.cnt=-1 loop dim ID,5,7 //最大5グループ、各グループ7個まで dim msg,7 init=1 return #deffunc radioUnInit //画面クリアの際に呼ぶ事で、これまでのボタンの情報をリセット //多少はメモリの節約になる dim count,1 dim ID,1 dim sel,1 dim msg,1 init=0 return *radioPush tmp=stat repeat 5 if(tmp=ID.cnt.0):sel.cnt=0:break if(tmp=ID.cnt.1):sel.cnt=1:break if(tmp=ID.cnt.2):sel.cnt=2:break if(tmp=ID.cnt.3):sel.cnt=3:break if(tmp=ID.cnt.4):sel.cnt=4:break if(tmp=ID.cnt.5):sel.cnt=5:break if(tmp=ID.cnt.6):sel.cnt=6:break loop return #deffunc radioCheck //メインループ内で呼んでもらう。キー操作の受付のため必要。 if(init==0):return await GetMessage varptr(msg),0,0,0 if(stat==-1)or(stat==0):return IsDialogMessage hwnd,varptr(msg) if(stat):return TranslateMessage varptr(msg) DispatchMessage varptr(msg) return #defcfunc getRadioState int p1 //現在選択されている項目のインデックスを取得 //p1 グループ番号 if(init==0):return -1 //初期化前 if(p1<0):return -2 //グループ番号が無効 if(p1>5):return -2 //グループ番号が無効 return sel.p1 #deffunc setRadioState int p1,int p2 //選択状態の変更 //p1 グループ番号 //p2 変更後選択項目のインデックス if(init==0):return -1 //初期化前 if(p1<0):return -2 //グループ番号が無効 if(p1>5):return -2 //グループ番号が無効 if(sel.p1!=-1):sendmsg objinfo_hwnd(ID.p1.(sel.p1)),$F1,0,0 //BM_SETCHECKでチェックを入れる sendmsg objinfo_hwnd(ID.p1.p2),$F1,1,0 //BM_SETCHECKでチェックを入れる sel.p1=p2 return #deffunc setTabstop int p1 //p1で指定したIDのオブジェクトにWS_TABSTOPを設定 //これを入れないと、ラジオボタン以外にTABキーでフォーカスされない GetWindowLong objinfo(p1,2),-16 SetWindowLong objinfo(p1,2),-16,stat | $10000 //WS_TABSTOP return //-------------------------------------- // モジュール定義の終わり //-------------------------------------- #global #endif //-------------------------------------- // モジュール定義の動作サンプル //-------------------------------------- #if(0) syscolor 15:boxf font MSGOTHIC,32 objmode 2 pos 50,50 winobj "BUTTON","グループ",0,$54000107,250,400 //$54000107=WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_GROUPBOX | BS_LEFT //WS_CLIPSIBLINGSの意味は不明だが、サンプルに合ったのでつけておく pos 70,90 objsize 200,40 radio "ラジオ0",1,0 radio "ラジオ1",0,0 radio "ラジオ2",0,1 radio "ラジオ3",0,0 radio "ラジオ4",0,0 pos 350,50 winobj "BUTTON","グループ",0,$54000107,250,400 pos 370,90 radio "ラジオ0",1,0 radio "ラジオ1",0,0 radio "ラジオ2",0,0 radio "ラジオ3",0,0 radio "ラジオ4",0,0 //背景色設定・グループ名のフォント変更 省略 mes "" button gosub "check",*check setTabstop stat repeat radioCheck getkey key,13 if(key):gosub *check loop *check if(getRadiostate(1)<0):return if(getRadiostate(1)<0):return dialog getRadiostate(0) dialog getRadiostate(1) return #endif //------------------------------------------------------------------------------ // End of mod_radioButton.hsp //------------------------------------------------------------------------------
この改良バージョンのポイントは、多重 include 禁止の対策と
一番下の「モジュール定義の動作サンプル」に
「#if(0)」を使ってる点でしょうかね。

モジュールの書き方の参考にどうぞ。



eoe

リンク

2017/8/22(Tue) 03:21:16|NO.81056

なんかメッセージループをスクリプトで行う方法で解決されてるみたいですが
あのサンプルは、やろうとすれば無理やりになることを示したかったものであり
私としては最初から言ってる通りやめた方がいいと思います。
Fubukiさんはメッセージループのことをよくわかってないみたいですしどのような副作用があるかもわからないでしょうし。



Fubuki

リンク

2017/8/22(Tue) 03:48:35|NO.81057

ご指摘ありがとうございます。

修正させていただきました。

4.の件については、他に様々なモジュールとの共用が考えられる(私はテキストボックスの背景色変更やメニューバーからの操作、画面サイズ変更によるオブジェクトサイズ・配置変更を実装済み)ため、*radioCheck内でawaitを入れる事としました。この方法が、一番相性問題を発生させにくく、どのようなソフトに組み込むとしてもメインのコードへの影響が少ないかと考えたためです。

 WS_CLIPSIBLINGS についても、MSDNの日本語訳がおかしくて困っておりました。(機械翻訳なので仕方ないですが)


 まだまだ勉強不足ですが、手元にあるモジュールもきちんとまとめて将来的に公開できるよう、勉強してまいります。



掘木

リンク

2017/8/23(Wed) 19:42:31|NO.81079

解決してますが、後々問題になりそうな点について補足。

>Fubukiさん
他のモジュールとの相性です?それらの中の実装はoncmdで動作するコードと推測できますが…

awaitは1命令でメッセージループを構成するような命令なのだから、それを入れると
「イベントの発生タイミングによって処理ルーチンを変更する」ことになりますよ。

もし、メッセージループをコード上に記述してなお、
・awaitやwait、stopがないコードを回しているとフリーズしたような状態になる
・on系命令がこれらの命令のタイミングでジャンプするため必要
といった感覚でawaitを入れているのなら、それは違いますよ。


>科学太郎さん
onexitはWM_CLOSE発生時のHSPWindowの基本動作です。(OpenHSPを見てみるといいかと)
oncmdで処理しない限りメッセージループから脱出する前にonexit先のラベルに飛びます。
(WM_CLOSEがPostQuitMessageを呼んでいるので)
そしてメッセージループの脱出後に終了処理は書けるでしょうけども、そこで終了を(基本的に)拒否できません。
WM_QUITを握りつぶす/GetMessageのエラー発生でプログラムを続行する ことになるからです。


オマケ:
IsDialogMessageはダイアログウィンドウにおいて、
Enterキーを要求しないコントロールに対してEnterキーを送り出されるとき、親?ウィンドウにWM_COMMANDを送り出します。
実際は標準ウィンドウであっても、標準の決定ボタンID(IDOK(1))が(存在する/しないにかかわらず)送り出されているように見えます。
この動作がWindows標準機能なのであれば(環境依存でないなら)、getkeyでEnterキーをキー入力待ちする必要がないです。

残念ながらこちらではこの動作が標準動作なのか環境依存なのかを明記した資料を見つけられませんでした。
詳しい方なら…。(まるなげ)



科学太郎

リンク

2017/8/24(Thu) 06:51:06|NO.81085

掘木さんへ。
> そしてメッセージループの脱出後に終了処理は書けるでしょうけども、そこで終了を(基本的に)拒否できません。
確かに無理ですね。ここでは。

> WM_QUITを握りつぶす/GetMessageのエラー発生でプログラムを続行する ことになるからです。
GetMessage関数で抜けたら end するしかないからね。

Fubukiさんへ。
GetMessage関数を使わずに自力で処理する方法を紹介します。

//------------------------------------------------------------------------------ // ラジオボタンのグループ化(2) by 科学太郎 //------------------------------------------------------------------------------ // @URL(http://hsp.tv/play/pforum.php?mode=all&num=81016)→「キーボードから正しく操作できるラジオボタンの設置」 //------------------------------------------------------------------------------ #include "User32.as" //-------------------------------------- // 記号定数(API定数) //-------------------------------------- #const global BM_GETCHECK $000000F0 #const global BM_SETCHECK $000000F1 #const global BM_SETSTYLE $000000F4 #const global BM_CLICK $000000F5 #const global BS_AUTORADIOBUTTON $00000009 # #const global GWL_STYLE $FFFFFFF0 #const global WS_TABSTOP $00010000 #const global WS_GROUP $00020000 #const global VK_SHIFT $00000010 //-------------------------------------- // 列挙定数(オブジェクトID) //-------------------------------------- #enum RID_RADIO10=0 #enum RID_RADIO11 #enum RID_RADIO12 #enum RID_RADIO13 #enum RID_RADIO14 # #enum RID_RADIO20 #enum RID_RADIO21 #enum RID_RADIO22 # #enum RID_RADIO30 #enum RID_RADIO31 #enum RID_RADIO32 #enum RID_RADIO33 # #enum MAX_CONTROL //-------------------------------------- // メイン部 //-------------------------------------- *Init n=0 ;作業用変数 nFocus=0 ;フォーカス(今回) nFocus2=0 ;フォーカス(前回) nRadio1=0 ;グループ nRadio2=1 ;グループ nRadio3=3 ;グループ *Main screen 0,640,480,SCREEN_NORMAL|SCREEN_FIXEDSIZE syscolor 15:boxf:color:title "ラジオボタンのグループ化(2) by 科学太郎" ;配置(グループ) objsize 200,25 mes "" repeat 5 button gosub strf("グループ Д薀献ボタン(%d)",cnt+10), *RadioButton1 SetGroupTabStop objinfo_hwnd(stat) loop ;配置(グループ) objsize 200,25 mes "" repeat 3 button gosub strf("グループ◆Д薀献ボタン(%d)",cnt+20), *RadioButton2 SetGroupTabStop objinfo_hwnd(stat) loop ;配置(グループ) objsize 200,25 mes "" repeat 4 button gosub strf("グループ:ラジオボタン(%d)",cnt+30), *RadioButton3 SetGroupTabStop objinfo_hwnd(stat) loop ;初期値 SetRadioButton RID_RADIO10,RID_RADIO14,nRadio1 SetRadioButton RID_RADIO20,RID_RADIO22,nRadio2 SetRadioButton RID_RADIO30,RID_RADIO33,nRadio3 ;設定(フォーカス) objsel(RID_RADIO10+nRadio1) repeat redraw 0 ;キー調査 stick n,$FFF if(n & %0011):KeyMovePrev ;逆方向([←][↑]キー) if(n & %1100):KeyMoveNext ;順方向([→][↓]キー) if(n & $0400):KeyTabStop ;タブストップ([TAB]キー) ;デバッグ情報 DrawDebug redraw 1 await 100 loop stop //-------------------------------------- // グループ,料択取得 //-------------------------------------- *RadioButton1 GetRadioButton RID_RADIO10,RID_RADIO14,nRadio1 return //-------------------------------------- // グループ△料択取得 //-------------------------------------- *RadioButton2 GetRadioButton RID_RADIO20,RID_RADIO22,nRadio2 return //-------------------------------------- // グループの選択取得 //-------------------------------------- *RadioButton3 GetRadioButton RID_RADIO30,RID_RADIO33,nRadio3 return //-------------------------------------- // WS_GROUPとWS_TABSTOPを設定 //-------------------------------------- #deffunc SetGroupTabStop int _wnd_ SendMsg(_wnd_),BM_SETSTYLE,BS_AUTORADIOBUTTON,0 if(cnt==0){ GetWindowLong(_wnd_),GWL_STYLE SetWindowLong(_wnd_),GWL_STYLE,stat|WS_GROUP|WS_TABSTOP } return //-------------------------------------- // ラジオボタンの項目番号を設定 //-------------------------------------- #deffunc SetRadioButton int _idFirst_,int _idLast_,int _no_ repeat((_idLast_)-(_idFirst_)+1),(_idFirst_) SendMsg objinfo_hwnd(cnt),BM_SETCHECK,0,0 loop SendMsg objinfo_hwnd(_idFirst_+_no_),BM_SETCHECK,1,0 return //-------------------------------------- // ラジオボタンの項目番号を取得 //-------------------------------------- #deffunc GetRadioButton int _idFirst_,int _idLast_,var _no_ repeat((_idLast_)-(_idFirst_)+1),(_idFirst_) SendMsg objinfo_hwnd(cnt),BM_GETCHECK,0,0 if(stat):_no_=(cnt)-(_idFirst_):break loop return(_no_) //-------------------------------------- // [←][↑]キーの移動処理 //-------------------------------------- #deffunc KeyMovePrev objsel -1:nFocus=stat SendMsg objinfo_hwnd(nFocus),BM_SETCHECK,0,0 ;フォーカスを戻る GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & WS_GROUP){ repeat nFocus++:if(nFocus>=MAX_CONTROL):nFocus=0 GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & WS_GROUP):break loop } nFocus--:if(nFocus<0):nFocus=(MAX_CONTROL-1) ;フォーカスの設定 objsel nFocus SendMsg objinfo_hwnd(nFocus),BM_SETCHECK,1,0 SendMsg objinfo_hwnd(nFocus),BM_CLICK,0,0 return //-------------------------------------- // [→][↓]キーの移動処理 //-------------------------------------- #deffunc KeyMoveNext objsel -1:nFocus=stat SendMsg objinfo_hwnd(nFocus),BM_SETCHECK,0,0 ;フォーカスを進む nFocus++:if(nFocus>=MAX_CONTROL):nFocus=0 GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & WS_GROUP){ repeat nFocus--:if(nFocus<0):nFocus=(MAX_CONTROL-1) GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & WS_GROUP):break loop } ;フォーカスの設定 objsel nFocus SendMsg objinfo_hwnd(nFocus),BM_SETCHECK,1,0 SendMsg objinfo_hwnd(nFocus),BM_CLICK,0,0 return //-------------------------------------- // [TAB]キーの移動処理 //-------------------------------------- #deffunc KeyTabStop\ local szClass dim szClass,1024 objsel -1:nFocus=stat if(nFocus==nFocus2):return ;ボタンクラスのチェック GetClassName objinfo_hwnd(nFocus),varptr(szClass),1024 if(szClass!="1953789250"):return ;BS_AUTORADIOBUTTONスタイル GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & $000F)!=BS_AUTORADIOBUTTON:return ;順方向/逆方向 getkey n,VK_SHIFT if(n){ ;[SHIFT]+[TAB]キー repeat GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & WS_TABSTOP):break nFocus--:if(nFocus<0):nFocus=(MAX_CONTROL-1) loop } else{ ;[TAB]キー repeat GetWindowLong objinfo_hwnd(nFocus),GWL_STYLE if(stat & WS_TABSTOP):break nFocus++:if(nFocus>=MAX_CONTROL):nFocus=0 loop } ;フォーカスの設定 objsel nFocus return //-------------------------------------- // デバッグ用のスタイル監視 //-------------------------------------- #deffunc DrawDebug syscolor 15:boxf:color ;スタイルの監視 pos 200,0 repeat MAX_CONTROL GetWindowLong objinfo_hwnd(cnt),GWL_STYLE if(stat & WS_GROUP):mes "" mes strf("id%02d=$%08X",cnt,stat) loop ;選択変数の監視 pos 400,0 mes "" mes strf("nRadio1=%d",nRadio1) mes strf("nRadio2=%d",nRadio2) mes strf("nRadio3=%d",nRadio3) return //------------------------------------------------------------------------------ // End of sample196b(ラジオボタンのグループ化).hsp //------------------------------------------------------------------------------
この方法ならば、純粋にHSPだけの命令ですから安全かと思います。



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