2016-11-25 10 views
1

質問に正しい言い回しができても問題は解決しないのかどうかは分かりません。私はKillFocusで両方とも検証する2つのボックスを持っています。ユーザーが[次へ]ボタンを押した場合に呼び出されるもう1つのメソッドは、続行できるかどうかを評価するメソッドを呼び出し、これらのフィールドを検証します。WM_KEYDOWNプロセスを続行するプログラムを停止する

このコードベースの長さによって、これを変更すると別の場所で問題が発生するため、シーケンスを続ける方法を変更せずにこれを回避する方法を見つける必要があります。ここにいくつかのシナリオがあります。

ユーザーがフィールド1に無効な値を入力し、enterキーを押すと、プログラムはキルフォーカスメソッドを起動し、エラーメッセージを表示します。Enterキーが次のボタンを押した後、再度(別のMsgBoxの同じエラー)。彼らが手動でunfocusしないと、Enterを押すと、常に2つのメッセージボックスが表示されます。

私はこれが、次にcanをコールするのではなく、フォーカスを殺したenterを押したことが原因だと思います。

KillFocusメソッドで失敗した場合、WM_KEYDOWNトレイル全体を停止する方法はありますか?

これは少し漠然としていると、私は起こっていると信じています。

+3

'WM_KILLFOCUS'で検証するのは面倒です。もし私があなただったら、私はこの問題に対する別の解決策を見つけるでしょう。 –

+0

@DavidHeffernan WM_KILLFOCUSのやり方でフィールドを検証する他の方法について知っていますか?これがチームが悲しいことにしたがっている方法です! https://blogs.msdn.microsoft.com/oldnewthing/20040419-00/?p=39753では、それが悪い方法だと説明しています。彼らはすべて私が2004年に抱えていた問題を経験しました! –

+4

チームにその記事を表示します。次に彼らがどれほど毅然としているかを見てください –

答えて

1

@DavidHeffernan WM_KILLFOCUSのやり方でフィールドを検証する方法は他にもありますか?

私は提案をすることができます。 EN_CHANGEハンドラでエディットコントロールの入力を検証することができます。ドキュメントから:

編集コントロールでテキストが変更されている可能性がある操作をユーザーが実行したときに送信されます。

ユーザーが何か入力するたびに、データを検証するのに適したこの通知が表示されます。

データが無効の場合は、を無効にします。次のボタンはEnableWindowを使用し、何とかエラーを示します。

EM_SHOWBALLOONTIPを使用すると、ツールチップにエラーメッセージが表示されたり、エディットコントロールの背景色を赤色に変更することができます。

以下は、私の要点を示す小さな例です。もちろん、より良いエラーチェックを追加する必要がありますが、主なアイデアがあります:

#include <windows.h> 
#include <CommCtrl.h> 

#define IDC_BTN_NEXT 1000 
#define IDC_BOX1  2000 
#define IDC_BOX2  3000 

// enable Visual Styles 
#pragma comment(linker, "/manifestdependency:\"type='win32' \ 
         name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ 
         processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \ 
         language='*'\"") 

// link with Common Controls library 
#pragma comment(lib, "comctl32.lib") 

void onBtnNext() 
{ 
    MessageBeep(0); 
} 

void onKillFocus(HWND box) 
{ 
    //==================== these are needed to disable Next button 
    HWND hwnd = ::GetParent(box); 

    if (NULL == hwnd) // critical error 
     return;   // TODO: add error handling 

    HWND btnNext = ::GetDlgItem(hwnd, IDC_BTN_NEXT); 

    if (NULL == btnNext) // critical error 
     return;    // TODO: add error handling 
    //============================================================== 

    int len = ::GetWindowTextLength(box); 

    if (0 == len) // it is ok, empty text, just return 
     return; 

    // if possible, use std::wstring here, I assumed you can't... 
    wchar_t *txt = new wchar_t[len +1];  

    if (0 == ::GetWindowText(box, txt, len + 1)) // critical error, according to documentation 
    { 
     // TODO: add error handling 
     delete[] txt; 
     return;          
    } 

    //====== simple validation for illustration only, treat uppercase letter as error 
    int isTextValid = ::isupper(txt[0]); 

    for (int i = 1; 0 == isTextValid && i < (len + 1); isTextValid = ::isupper(txt[++i])); 

    delete[] txt; 
    //============================================== 

    if (isTextValid) 
    { 
     EDITBALLOONTIP ebt; 

     ebt.cbStruct = sizeof(EDITBALLOONTIP); 
     ebt.pszText = L" Tooltip text"; 
     ebt.pszTitle = L" Tooltip title"; 
     ebt.ttiIcon = TTI_ERROR_LARGE; 

     if (!::SendMessage(box, EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt)) 
     { 
      //TODO: tooltip won't show, handle error 
     } 

     EnableWindow(btnNext, FALSE); // disable Next button 

     return;  // our work is successfully done 
    } 

    if (!::SendMessage(box, EM_HIDEBALLOONTIP, 0, 0)) 
    { 
     //TODO: tooltip won't hide, handle error 
    } 

    EnableWindow(btnNext, TRUE); // enable Next button 
} 

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch (msg) 
    { 
    case WM_CREATE: 
    { 
     HWND hwndBox1 = CreateWindowEx(0, WC_EDIT, L"", 
      WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 
      20, 20, 250, 20, hwnd, (HMENU)IDC_BOX1, 
      ((LPCREATESTRUCT)lParam)->hInstance, 0); 

     if (NULL == hwndBox1) // add better error handling, this is for illustration only 
      return -1; 

     HWND hwndBox2 = CreateWindowEx(0, WC_EDIT, L"", 
      WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 
      20, 50, 250, 20, hwnd, (HMENU)IDC_BOX2, 
      ((LPCREATESTRUCT)lParam)->hInstance, 0); 

     if (NULL == hwndBox2) // add better error handling, this is for illustration only 
      return -1; 

     HWND hwndBtnNext = CreateWindowEx(0, WC_BUTTON, L"Next", 
      WS_CHILD | WS_VISIBLE | BS_CENTER | BS_DEFPUSHBUTTON, 
      20, 80, 50, 25, hwnd, (HMENU)IDC_BTN_NEXT, 
      ((LPCREATESTRUCT)lParam)->hInstance, 0); 

     if (NULL == hwndBtnNext) // add better error handling, this is for illustration only 
      return -1; 

    } 
     return 0L; 
    case WM_COMMAND:   
    { 
     switch (HIWORD(wParam)) 
     { 
     case BN_CLICKED: 
     { 
      if (LOWORD(wParam) != IDC_BTN_NEXT) 
       break; 

      onBtnNext(); 
     } 
      break; 
     case EN_CHANGE: 
     { 
      if (LOWORD(wParam) != IDC_BOX1 && (LOWORD(wParam) != IDC_BOX2)) 
       break; 

      onKillFocus((HWND)lParam); 
     } 
      break; 
     default: 
      break; 
     } 
    } 
     break; 
    case WM_CLOSE: 
     ::DestroyWindow(hwnd); 
     return 0L; 
    case WM_DESTROY: 
    { 
     ::PostQuitMessage(0); 
    } 
     return 0L; 
    default: 
     return ::DefWindowProc(hwnd, msg, wParam, lParam); 
    } 
    return 0; 
} 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, 
    int nCmdShow) 
{ 
    WNDCLASSEX wc; 
    HWND hwnd; 
    MSG Msg; 

    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style = 0; 
    wc.lpfnWndProc = WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hInstance; 
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = L"Main_Window"; 
    wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION); 

    if (!RegisterClassEx(&wc)) 
     return 0; 

    INITCOMMONCONTROLSEX iccex; 
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); 
    iccex.dwICC = ICC_STANDARD_CLASSES; 
    InitCommonControlsEx(&iccex); 

    hwnd = CreateWindowEx(0, L"Main_Window", L"Test", 
     WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION, 
     50, 50, 305, 160, NULL, NULL, hInstance, 0); 

    ShowWindow(hwnd, nCmdShow); 
    UpdateWindow(hwnd); 

    while (GetMessage(&Msg, NULL, 0, 0) > 0) 
    { 
     TranslateMessage(&Msg); 
     DispatchMessage(&Msg); 
    } 
    return Msg.wParam; 
} 
+0

遅れて申し訳ありませんが、私は以下に示すように非従来型の方法でこれを解決しましたが、将来的にはあなたのソリューションを使用することに間違いありません。 –

+1

@ダニエルシムズ:アップホート+正式な私の答えの受け入れをありがとう。悲しいことに、あなたの慣習的でない方法は、OPにリンクした記事で指摘されている問題を解決しません。あなたのコードを微調整する場合は、私の答えに従って、コメントを残して質問をしてください。私の答えの全体的なポイントは、テキストの検証は 'EN_UPDATE'でのみ行われるため、' onNextButton'ハンドラからのテキストの検証を削除することで二重検証を削除することができます。 – AlwaysLearningNewStuff

0

問題は「型破り」な方法で解決されたが、それが働きました。私はデバッグを通して、プログラムがボックスで2回フォーカスを失ったことを知りました。一度ENTERを押すとメッセージボックスがポップアップしたときです。

プログラムでエラーチェックを2回実行しないように静的ブールを使用しました。それはこのようなものになります - 静的なブール値は限りメソッドが実行されるためだけに生きているようフォーカスが、二回表示されたメッセージボックスを停止殺害されたときに、これを使用することにより

void onKillFocus() 
{ 
    static bool isValidated = false; 
    if(!isValidated) 
    { 
     isValidated = true; 
     if(/*ValidationCheck*/) 
     { 
      //messagebox for error 
     } 
    } 
} 

を、検証は一度だけ実行されますkillfocusが呼び出されるたびにリセットされることを意味します。

関連する問題