簡體   English   中英

如何防止 MFC 對話框在 Enter 和 Escape 鍵上關閉?

[英]How to prevent MFC dialog closing on Enter and Escape keys?

我知道一種防止 MFC 對話框在按下EnterEsc鍵時關閉的方法,但我想了解該過程的更多詳細信息以及執行此操作的所有常用替代方法。

在此先感謝您的幫助。

當用戶在對話框中按下 Enter 鍵時,會發生兩種情況:

  1. 該對話框有一個默認控件(請參閱CDialog::SetDefID() )。 然后將帶有此控件 ID 的 WM_COMMAND 發送到對話框。
  2. 該對話框沒有默認控件。 然后將 ID = IDOK 的 WM_COMMAND 發送到對話框。

對於第一個選項,可能會發生默認控件的 ID 等於 IDOK。 那么結果將與第二個選項中的結果相同。

默認情況下,類CDialog有一個用於調用CDialog::OnOk()WM_COMMAND(IDOK)處理程序,這是一個虛函數,默認情況下它調用EndDialog(IDOK)來關閉對話框。

因此,如果您想避免關閉對話框,請執行以下操作之一。

  1. 將默認控件設置為IDOK以外的其他控件。
  2. 將處理程序設置為不調用EndDialog()WM_COMMAND(IDOK) EndDialog()
  3. 覆蓋CDialog::OnOk()並且不調用基本實現。

關於 IDCANCEL,它是類似的,但沒有等效的SetDefID()並且 ESC 鍵是硬編碼的。 所以為了避免對話框被關閉:

  1. 將處理程序設置為不調用EndDialog()WM_COMMAND(IDCANCEL) EndDialog()
  2. 覆蓋CDialog::OnCancel()並且不調用基本實現。

上一個答案有一個替代方案,如果您希望仍然有一個確定/關閉按鈕,這將很有用。 如果您覆蓋 PreTranslateMessage 函數,您可以像這樣捕獲 VK_ESCAPE / VK_RETURN 的使用:

BOOL MyCtrl::PreTranslateMessage(MSG* pMsg)
{
    if( pMsg->message == WM_KEYDOWN )
    {
        if(pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
        {
            return TRUE;                // Do not process further
        }
    }

    return CWnd::PreTranslateMessage(pMsg);
}

@the-forest-and-the-trees 的回答很好。 除了@oneworld 解決的一種情況。 您需要過濾不是對話窗口的消息:

BOOL CDialogDemoDlg::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->hwnd == this->m_hWnd && pMsg->message == WM_KEYDOWN)
    {
        if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
        {
            return TRUE;                // Do not process further
        }
    }
    return CWnd::PreTranslateMessage(pMsg);
}

記得在頭文件中添加virtual

在處理 Dialog 樣式的 MFC 應用程序時,框架會自動硬編碼一些必須覆蓋的項目,以防止應用程序在按下 ESC 或 Enter 鍵時退出。 但是有一種非常簡單的方法不需要任何特殊的東西,例如實現非常不推薦的 PreTranslateMessage()。

有三個功能需要到位:

  1. OnCancel() 函數覆蓋基類版本而不是調用它。 這可以防止 ESC 鍵關閉應用程序。
  2. OnOK() 函數覆蓋基類版本而不是調用基類。 這可以防止 Enter 鍵關閉應用程序。
  3. 由於您現在已阻止關閉對話框窗口,因此您現在必須實現 OnClose() 事件處理程序。 當 Windows 的“X”按鈕或系統命令 Close Alt+F4 被單擊時,此函數處理程序將進行處理。 現在為了關閉應用程序,如果需要,您可以調用其他函數 OnOK()、OnCancel() 之一的基類版本,以實際關閉應用程序。 此時,您現在可以完全控制應用程序的關閉方式。

第1步

在標題中,添加三個函數原型。 如果您想添加 WM_CLOSE 事件處理程序,您可以使用類向導,但只需輸入它就非常簡單。

// DefaultDialogAppDlg.h
//

class CDefaultDialogAppDlg : public CDialogEx
{
    // ... other code
  
protected:
    virtual void OnCancel(){}    // inline empty function
    virtual void OnOK(){}        // inline empty function
public:
    afx_msg void OnClose();      // message handler for WM_CLOSE

    // ...other code
};

第2步

在 .cpp 文件中,將 ON_WM_CLOSE() 條目添加到消息映射和三個函數的定義中。 由於 OnCancel() 和 OnOK() 通常為空,如果需要,您可以將它們內聯到標頭中(看看我在第 1 步中做了什么?)。

.cpp 文件將包含以下內容:

// DefaultDialogAppDlg.cpp

// ... other code

BEGIN_MESSAGE_MAP(CDefaultDialogAppDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_CLOSE()        // WM_CLOSE messages are handled here.
END_MESSAGE_MAP()

// ... other code

void CDefaultDialogAppDlg::OnClose()
{
    // TODO: Add exit handling code here
    // NOTE: to actually allow the program to end, call the base class
    // version of either the OnOK() or OnCancel() function.
    
    //CDialogEx::OnOK();      // returns 1 to theApp object
    CDialogEx::OnCancel();    // returns 2 to theApp object
}

我只是覆蓋 OnOk 事件,而不是將消息傳遞給父對話框,什么都不做。
所以這樣做基本上很簡單:

void OnOk() override { /*CDialog::OnOK();*/ }

這應該可以防止對話框在按下回車/回車鍵時關閉。

確保你沒有#define CUSTOM_ID 2因為2已經定義為轉義而我認為1是為輸入定義的? 如果我錯了,請糾正我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM