【问题标题】:How to kill focus of "edit" control on "Enter" key press如何在“Enter”键按下时取消“编辑”控件的焦点
【发布时间】:2013-06-26 04:23:08
【问题描述】:

我在主函数中创建了一个主窗口。在 WM_CREATE 消息的主窗口过程中,我使用系统“编辑”窗口类创建了一个编辑控件,它作为父窗口的子窗口。我希望在编辑控件中按下回车键时将焦点转移到主窗口。因为我使用了系统类,所以我无权访问它的过程。 我在 Visual Studio 10 中为此使用 C++ 由于我是 win32 应用程序的新手,所以无论代码多长,我都想要一个简单的解决方案

【问题讨论】:

  • 我真的不记得是否有更好的方法,但是子类化控件很常见。
  • 一些关于子类化的帮助
  • 网上有很多例子,SetWindowSubclass可以让你的生活更轻松。
  • 嗯,“无论代码多长,一个简单的解决方案”。这不是矛盾吗?长代码往往比较简单。 :-)
  • 简单代码意味着不使用高级功能等。

标签: c++ c winapi


【解决方案1】:

如果您的窗口只有一个可聚焦控件(例如编辑控件),则该控件将始终获得焦点。你不能有一个没有焦点控件的窗口,并且父窗口本身是不可聚焦的(即不能有焦点)。

因此,如果您还没有另一个可聚焦控件,您首先需要向窗口添加另一个可聚焦控件(我无法从问题中看出)。例如,您可以添加“确定”或“取消”按钮。这样,每当您取消编辑控件的焦点时,按钮都可以获得焦点。

然后,您需要对编辑控件进行子类化,以便处理其按键事件(例如 WM_KEYDOWNWM_KEYUP)。要子类化单个窗口,请调用 SetWindowLongPtr 函数并将窗口句柄与 GWLP_WNDPROC 标志和指向自定义窗口过程的指针一起传递。这有效地用您的自定义窗口过程替换了该类控件的默认窗口过程。例如:

// Stores the old original window procedure for the edit control.
WNDPROC wpOldEditProc;

// The new custom window procedure for the edit control.
LRESULT CALLBACK CustomEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_KEYDOWN:
        {
            if (wParam == VK_RETURN)
            {
                // The user pressed Enter, so set the focus to the other control
                // on the window (where 'hwndOther' is a handle to that window).
                SetFocus(hwndOther);

                // Indicate that we processed the message.
                return 0;
            }
        }
    }

    // Pass the messages we don't process here on to the
    // original window procedure for default handling.
    CallWindowProc(wpOldEditProc, hWnd, msg, wParam, lParam);
}
// ----- Add to the parent window's WM_CREATE: -----

// Create the edit control
HWND hwndEdit = CreateWindowEx(...);

// Subclass it.
wpOldEditProc = (WNDPROC)SetWindowLongPtr(hwndEdit,
                                          GWLP_WNDPROC,
                                          (LONG_PTR)CustomEditProc);

// Show it.
ShowWindow(hwndEdit, SW_SHOW);

// ... your other code (e.g. creating and showing the other control)
// ----- Add to the parent window's WM_DESTROY: -----

// Unsubclass the edit control.
SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR)wpOldEditProc);

// ... your other code (e.g. calling PostQuitMessage(...) to close your app)

关于子类化窗口的进一步阅读是here on MSDN。那里的示例代码(以及网络上的许多其他地方)假定您在 dialog 窗口中继承了一个编辑控件。因为对话框是自动处理大量键盘处理的特殊类型的父窗口,所以您需要采取额外的步骤来克服对话框完成的这种默认处理。如果您使用的是使用CreateWindowEx 创建的常规窗口,则没有必要。

如果您希望多个编辑控件在响应某些按键时都以相同的方式进行,注册自定义窗口子类会更加简洁和更好的设计。鉴于上述代码仅对单个编辑控件对象进行了子类化,这种方法将创建一种新类型的自定义编辑控件类。您可以根据需要创建任意数量的这种新型编辑控件的实例,并且它们的行为方式都相同。

但我不会在这里讨论如何做到这一点。 You can find the code online 如果您有兴趣,并且您的特定用例使它变得更复杂一些。为了改变焦点,控件必须知道它应该将焦点设置到哪个其他控件。这很难在全球范围内处理。建议使用对话窗口作为父窗口。它会自动管理 Z 顺序并为您设置焦点。

【讨论】:

  • 非常感谢您的帮助,每当用户使用 SetFocus(hparent,...) 在父窗口中单击时,我已经设法消除焦点,但我希望它在输入键时完成 I想知道我们是否可以在不使用 subclsing 的情况下从编辑控件发送到父窗口的消息中找出它。
  • @Engr 否。您需要子类化才能获取消息。编辑控件不会将有关 Enter 键按下的消息转发到其父窗口。其他控件可能会这样做,但不能编辑控件。它们旨在将 Enter 按键解释为新行(在多行编辑控件中),或忽略它们。
猜你喜欢
  • 2023-03-27
  • 1970-01-01
  • 2019-03-10
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
相关资源
最近更新 更多