ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2024年4月27日(土) 23:41

全ての表示時間は UTC+09:00 です




新しいトピックを投稿する  トピックへ返信する  [ 5 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2008年6月01日(日) 03:49 
オフライン

登録日時: 2006年6月02日(金) 18:20
記事: 106
モーダルダイアログ上のエディットボックスでのキー入力メッセージ取得について
教えてください。

モーダルダイアログにエディットボックス(一行)が一つ、
その下にOKと書かれたボタンが一つあるとします。
そのエディットボックスに、例えば数字を入力してEnterキーを押すと
フォーカス*が下のOKボタンに移る、というようにしたいのですが、
(つまり数字を入力してEnterを二回タンタンと押せばOKボタンを押せる、
というような)
どうもうまくいきません。

ActiveBasicFanさんのHPで解説されていた「フック」という方法を試してみたの
ですが、エディットボックスを使うとなると少し勝手がちがうのかなと。。
下はそのソースです。(AB4.24 プロジェクト)
エディットボックスでのEnterキーの受付は出来るのですが、そこに何か処理を
書くと今度はOKボタンをEnterで押したときにもその処理に飛んでいってしまうのです。
コード:
'Hookのインストール
    hHook = SetWindowsHookEx(WH_GETMESSAGE,_
     AddressOf(GetMsgProc),  0,_
     GetWindowThreadProcessId(_
      GetDlgItem(hDialog1,EditBox1),NULL))
と書いたので「エディットボックスのメッセージループ」にのみ関係しているんじゃ
ないかと思うのですが、ボタンの方にも影響してしまいます。
これを回避するにはとあれこれ考えてはみるのですが、そんなにいい考えも無く、
フックというやり方以外にも何かあるのかなとも思ったり。。
 いずれにしても、もし良い方法があれば教えてください。


(* 単にフォーカスだけ移ればいいというのでも無いようです。
単にSetFocusなどでフォーカスをセットするだけでは
ボタンに点線は付くのですが、ボタン周りの黒枠が付きません。)


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2008年6月01日(日) 17:51 
オフライン

登録日時: 2005年5月31日(火) 18:51
記事: 473
お住まい: 新潟県
サブクラスを使うと簡単に実装できます。
自分の環境ではちゃんとエディットボックス内でエンターキーを押した時に、コマンドボタンにフォーカスが移りました。
ただ、コマンドボタンにフォーカスがある状態でエンターキー押しても押したことになりませんね。
ここもサブクラス化して、コマンドボタン上でエンターキーが押されたらっていうのを実装した方が良いんだろうか...。
なんかスッキリしません。
エンターキーを押したらフォーカスを移すんじゃなく、OKボタンが押されたことにするっていうのはダメなんですか?

追記
コマンドボタン上でスペースキー押すと、押したことになりますね。


通報する
ページトップ
投稿記事Posted: 2008年6月02日(月) 19:49 
オフライン

登録日時: 2006年6月02日(金) 18:20
記事: 106
7さん、レスありがとうごさいます。
教えていただいたサブクラスを使う方法、実行してみたのですが、
どうもこちらの環境(WinMe/AB4.24)ではうまく行かないようです。
エンターの入力を取ってくれなく、エディットのフォーカスが他へ移らないままです。
(こちらのプログラムの組み具合が悪いのかもしれません。もしそうだったら
申し訳ありません。)

実は「フック」という方法を試す前に、検索エンジンで調べて
"ActiveBasic講座「ウィンドウのサブクラス化(1)-実践」"というページを
見つけました。
http://www.2chab.net/pukiwiki/index.php ... C%C2%C1%A9
 "エディットボックスをサブクラス化してエディットボックス入力中の
リターンキーの入力を検出しメッセージボックスでエディットボックスの内容を
表示してみます"
という説明で、これはほとんど自分のやりたいことそのものズバリだと
思って見ながら組んでいたのですが、(そのページでは「メインウインドウ」で
作られていたので)、そのプログラムを「モーダルダイアログ」に移したところ、
動かなくなってしまいました。エンターキーの反応が無くなってしまい。

あれこれ考えながら、サブクラス内のメッセージ取得状態を見てみると、
(頂いたプログラムでは「#prompt」としてEditBoxProc()内先頭に
「Print "dwMsg=";dwMsg」と入れてみて下さい。)

モーダルダイアログを開き、エディットボックスをアクティブにして
ここで「a」キーを押すと、
dwMsg=135
dwMsg=256
dwMsg=135
dwMsg=258
dwMsg=642
dwMsg=257
とズララと表示され、
(二番目の"dwMsg=256"がWM_KEYDOWN、
最後の"dwMsg=257"がWM_KEYUPだと思います。)
しっかりとWM_KEYDOWNメッセージが取れていて
SelectCase分岐に入っていることが分かります。

ところが、同様に「エンター・キー」を押してみると、
dwMsg=135
dwMsg=135
dwMsg=257
と表示されWM_KEYUPはあるものの
WM_KEYDOWNが無い。。。

何故なんだろうと思いつつ、モーダルダイアログで
ダメなんならとりあえず出来てるメインウインドウで続けて
みようかなと思ったのですが
このメインウインドウでは「TABキーでのコントロール移動」が
効いていないことに気が付き、、、
そこでまた調べて、
「TABキーでのコントロール移動」のためには
Window Message Loop内に
「IsDialogMessage(hMainWnd, msgMain)」
という命令を挿入すれば良いとあったので、
早速そう書いて実行してみると確かにTAB移動が可能に、ところが、、
今度は肝心のエディットでのエンターキー受付が
効かなくなってしまっている。。。
これじゃモーダルダイアログの時と症状が同じ。

そんなこんなで他に方法はと思い前述の
「フック」という方法に辿り着いたのですが、
そこから先は初めの質問に書いた通りです。

感じとしては「IsDialogMessage」という命令が
エンターキーなどの特殊キーのメッセージを抱え込んじゃって
いるような印象を受けたんですが、詳しいメカニズムは
サッパリです。


エディットでのエンター決定、そこからOKボタンの
確定エンター押し、というのは、割とどこにでもある
それほど特別な機能でも無いような気がするので
出来れば是非実現したいと思っています。

それからご指摘のように「SetFocus」で単にフォーカスを
投げるやり方はいかにも不自然だと自分でも思います。
要するに、"エディットを抜けて、コントロール移動ループに
復帰(TABで次のコントロールに移るように)する"ということが
出来ればいいんですよね。ただそれが中々。

良い方法があればまた教えてください。レス、ありがとうございました。


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2008年6月02日(月) 21:38 
オフライン

登録日時: 2005年5月31日(火) 17:59
記事: 899
お住まい: 東京都
Windowsのダイアログでは、通常、Enterを押すだけでOKをクリックしたのと同じことになります。そこで勝手ながら、7さんもおっしゃっていた、「エンターキーを押したらフォーカスを移すんじゃなく、OKボタンが押されたことにする」ということで話をします。

Windowsのダイアログ(というよりIsDialogMessageで処理されるウィンドウ)では、Enter押下がOKボタンのクリックになるという取り扱いを受けるために、OKボタンのIDの値を1にするという取り決めがあります。ところが、AB4のRADでは、IDの値を個別に指定することができません。そのため、そのままではWindows共通のOKボタンの仕組みを扱えないのです。

そこで、次のようにしてプログラム上でOKボタンのIDを1にすれば、Enterを押したときにOKボタンのClickイベントが発生するようにできます。ダイアログでも、IsDialogMessage使用のウィンドウでも構いません。

1. CreateイベントにSetWindowLong(GetDlgItem(hMainWnd, CommandButton1), GWL_ID, IDOK)を加えます。hMainWndとCommandButton1を適当に書き換えてください。IDOKは値1の定数です。
2. RADの生成コードが機能しなくなるので、手動でClickイベントを呼ぶようにします。対象のウィンドウプロシージャ(MainWndProcなど)のEventCall_MainWndの1行を次のように置き換えます。中のMainWndの文字も書き換えてください。
コード:
If dwMsg = WM_COMMAND And LOWORD(wParam) = IDOK Then
	MainWnd_CommandButton1_Click()
Else
	MainWndProc = EventCall_MainWnd(hWnd, dwMsg, wParam, lParam)
End If
こうすると、ダイアログ・ウィンドウ上でEnterを押すとCommandButton1のClickイベントが発生するようになります。

あと、同様にEscキーでIDCANCEL = 2のボタンのクリックというものもあります。


通報する
ページトップ
投稿記事Posted: 2008年6月03日(火) 01:49 
オフライン

登録日時: 2006年6月02日(金) 18:20
記事: 106
レスありがとうございます。
引用:
1. CreateイベントにSetWindowLong(GetDlgItem(hMainWnd, CommandButton1), GWL_ID, IDOK)を加えます。hMainWndとCommandButton1を適当に書き換えてください。IDOKは値1の定数です。
2. RADの生成コードが機能しなくなるので、手動でClickイベントを呼ぶようにします。対象のウィンドウプロシージャ(MainWndProcなど)のEventCall_MainWndの1行を次のように置き換えます。中のMainWndの文字も書き換えてください。
教えていただいた通り、SetWindowLongでIDを書き変えると
上手く動きました!
(それにしてもSetWindowLongという命令は強力ですね。)

それから、
引用:
Windowsのダイアログでは、通常、Enterを押すだけでOKをクリックしたのと同じことになります。そこで勝手ながら、7さんもおっしゃっていた、「エンターキーを押したらフォーカスを移すんじゃなく、OKボタンが押されたことにする」ということで話をします。
これについては、よくWeb上の記入フォームなどに見られる、"エディットに入力して
Enterで確定すると、順次下のコントロールにフォーカスが移る"、という仕組みと
ハッキリ自分がごっちゃにしていたようです。
確かに改めてWindowsのダイアログを見てみると言われるようにEnterで
直接OK押しとなっていました。
コントロールの移動はTABキーが基本になっていますね。(カーソルキーでも
ボタンなどは移動しますが、一度エディットボックスなどに嵌るとカーソルキーは
エディット内のキャレットの移動になるので、TABキーでないと次へ移せません。)
なるほどなーと思いつつ、まだこの辺も改めて確かめないといけないことが多いなと
思いました。

 OKボタンをあらかじめエンターでの決定ボタンだと示し(=「標準のボタン」)、
それをMainWndProc等でWM_COMMANDと
wParamの下位ワードでOK押しを拾う。
そういうルールになっているんですね。
(それから「EscキーでIDCANCEL = 2のボタンのクリック」というのも
ありがとうございました。これで何とか「キーボードから操作出来る
Windowsの標準的なダイアログ」に手が伸ばせそうです。)

 7さん、イグトランスさん、レスありがとうございました。
またよろしくお願いします。


通報する
ページトップ
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 5 件の記事 ] 

全ての表示時間は UTC+09:00 です


オンラインデータ

このフォーラムを閲覧中のユーザー: Semrush [Bot] & ゲスト[16人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by ocean