OnKillFocusで次にフォーカスの行くコントロールは? – プログラミング – Home

OnKillFocusで次にフォーカス...
 
通知
すべてクリア

[解決済] OnKillFocusで次にフォーカスの行くコントロールは?


たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
Topic starter  

またお世話になります。たいちうです。
FAQだと思っていたのですが調べられなかったのでお願いします。

MFCで入力用のダイアログを作っています。
複数あるCEditで、OnKillFocusでそれぞれデータをチェックして、
入力エラーの場合はフォーカスを移さないようにしているのですが、
キャンセルボタンを押したときはそのままダイアログを閉じたいのです。

現在はOnCancelが呼ばれる前に、エラーチェックに引っかかり、
キャンセルできません。対処法ご存知の方、よろしくお願いします。

【環境】Windows2000, VC6.0+SP5, MFC, SDIから呼ぶモードレスダイアログ


引用未解決
トピックタグ
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

OnKillFocus()の引数では判定できないでしょうか。


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
Topic starter  

dairygoodsさま

早速の回答ありがとうございます。
そしてごめんなさい。

ON_EN_KILLFOCUS でマッピングしたOnKillFocuxHogeのことで、
CWnd::OnKillFocusではありません。
変な書き方をして申し訳ありませんでした。

OnKillFocuxHogeには引数はありません。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

とりあえず、次のような感じでどこにフォーカスが行ったか判別できました。

void CHemoDlg::OnKillFocusHoge()
{
if (GetFocus()->GetDlgCtrlID() == IDCANCEL) {
} else {
}
}

しかし、フォーカスがどこに行ったかで判断すると、
「キャンセル」ボタンを押しっぱなしにし、
ドラッグしてボタンのクリックをキャンセルする。
で、改めて「OK」を押す。
という抜け道ができてしまいます。

この問題は、KillFocusのタイミングで判定する限り、
回避不可能です。


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

dairygoodsさんも言われていますが、KillFocusを使うのはいい方法ではないです。
エディットコントロールならキーが入力されるたびとか、内容の変更が行われたとか
そういったタイミングで処理が出来たと思います。

ただ、私が思うに入力するたびにチェックするというのは実際にはダイアログの
インターフェースに馴染まないような気がします。入力するたびのチェックで出来るの
は、
せいぜい字種チェックぐらいでしょう。
最終的に入力が終わった後のチェックはOKボタン押下時に行い、
エラー項目にフォーカスを設定してエラーメッセージを出すというのが
インターフェイス的にはあっていると思います。
複数箇所ある場合は、直してOKを押すたびにフォーカスが別のところに移って
エラーのメッセージが出るといった流れになります。
インターフェイス的に馴染まない処理を行っているので
今回のような不整合がおこるのではないでしょうか。


返信引用
ATIS
 ATIS
(@ATIS)
ゲスト
結合: 22年前
投稿: 4
 

ひとつの方法として・・・

まずCEditとCButtonのコントロールをサブクラス化します。

サブクラス化したクラスのWM_SETFOCUSをインプリメントします。

OnSetFocus(CWnd* pOldWnd) の関数ができるので、
以下のコードでダイアログにメッセージを送信
チェック対象IDはpOldWndがあるので
chkID=::GetDlgCtrlID(pOldWnd->m_hWnd);で取り、
新しいフォーカスIDは
newID=::GetDlgCtrlID(this->m_hWnd);で取ります。

fl=::SendMessage(this->GetParentOwner()->m_hWnd,OR_CHECKUP,chkID,newID);

これでダイアログにWM_CHECKUP(#define OR_CHECKUP WM_USER+2等して登録しておいて)
メッセージが送信されてくるので、

ダイアログCPPファイルのメッセージマップに
ON_MESSAGE(OR_CHECKUP, OnCheckUp) を追加

ダイアログヘッダーのメッセージマップに
afx_msg LRESULT OnCheckUp( WPARAM wParam, LPARAM lParam ); を追加

実装部で
LRESULT CNewCtrl2Dlg::OnCheckUp( WPARAM wParam, LPARAM lParam )
{
if(lPalam==IDC_STOP) return 0L; //フォーカス先が中止ボタンの時は何もチェックしな
い。

if(wParam==IDC_EDIT1){
if(チェック項目){
GetDlgItem(IDC_EDIT1)->SetFocus();
return true; //チェックに引っかかったらTRUEをかえす。

}

return 0L;
}


返信引用
ATIS
 ATIS
(@ATIS)
ゲスト
結合: 22年前
投稿: 4
 

実装部間違えました。

実装部で
LRESULT CNewCtrl2Dlg::OnCheckUp( WPARAM wParam, LPARAM lParam )
{
if(lPalam==IDC_STOP) return 0L; //フォーカス先が中止ボタンの時は何もチェッ
クしな
い。

if(wParam==IDC_EDIT1){
if(チェック項目){
GetDlgItem(IDC_EDIT1)->SetFocus();
return true; //チェックに引っかかったらTRUEをかえす。
}
}

return 0L;
}

これの欠点:サブクラス化してないコントロールがあると、イベントがこない。
利点: チェック関数の中で、ループ掛けて項目をチェックすることも可能。


返信引用
ATIS
 ATIS
(@ATIS)
ゲスト
結合: 22年前
投稿: 4
 

んー自分の文章見て分かりずらい・・・^^;

要約すると、フォーカスを受け取ったコントロールで、
前のフォーカスのチェックするための、メッセージをダイアログに送る
ということです。

尚、複数項目を一度にチェックするループですが、
コントロールのタブオーダー順にIDを整列させておく必要があります。


返信引用
ATIS
 ATIS
(@ATIS)
ゲスト
結合: 22年前
投稿: 4
 

あぁ、また間違えた・・・

これでダイアログにWM_CHECKUP(#define OR_CHECKUP WM_USER+2等して登録しておいて)
メッセージが送信されてくるので、

これでダイアログにOR_CHECKUPです。


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
Topic starter  

レス大変送れて申し訳ありません。

> dairygoodsさま、PATIOさま

GetFocus()->GetDlgCtrlID()が求めていたものでした。
OnOK()でも最終的なチェックをしているので、抜け道については心配ありません。

今回の設計はインターフェース的に馴染まないのですかね。
最終チェックはOnOKですが、キーとなるいくつかのエディットコントロール
については、フォーカスを失ったときにチェックして以降の無駄な入力をさせ
ないようにする、という意図なんですが。よく考えてみます。

> ATISさま

丁寧な説明有難うございます。
ただ、ちょっとイレギュラーな処理をしたかっただけのようですので、
そのために全てのコントロールに手を加えるのはどうかと思っています。
サンプルは後ほどゆっくりと勉強させてもらいます。

皆様ご回答有難うございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました