【问题标题】:Sub-classing an edit control (in full window, NOT dialogue)对编辑控件进行子类化(在全窗口中,不是对话)
【发布时间】:2013-08-01 08:24:23
【问题描述】:

多年来我一直在尝试解决这个问题,但我完全被难住了!我正在尝试对编辑控件进行子类化,以便在按下回车键时进行捕获。

我看过很多其他关于使用 sn-ps 代码进行子类化的帖子,但我似乎无法在我的应用程序中实现它。如果我犯了一个愚蠢的错误,我深表歉意,但我根本无法弄清楚。

我知道这段代码写得不好并且没有错误检查,但我想发布尽可能少的代码来表达问题。

#include <Windows.h>
#include <wchar.h>

HWND editHWND;
WNDPROC wpOrigEditProc;

LRESULT APIENTRY EditSubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_CHAR)
    {
        //do my stuff
    }
    return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}


LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_CREATE:

        wpOrigEditProc = (WNDPROC) SetWindowLong(editHWND,GWL_WNDPROC, (LONG) EditSubclassProc);
        SetWindowLong(editHWND, GWL_WNDPROC,(LONG) wpOrigEditProc);
        break;

    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

int WINAPI wWinMain( HINSTANCE hInst,HINSTANCE,LPWSTR,INT )
{
    WNDCLASSEX wc = { sizeof( WNDCLASSEX ),CS_CLASSDC,MsgProc,0,0,
                      GetModuleHandle( NULL ),NULL,NULL,NULL,NULL,
                      L"My Window",NULL };
    RegisterClassEx( &wc );

    HWND hWnd = CreateWindowW( L"My Window",L"test application",
                              WS_OVERLAPPEDWINDOW,100,100,800,600,
                              NULL,NULL,wc.hInstance,NULL );

    editHWND = CreateWindow( L"edit",L"hi there",WS_VISIBLE | WS_CHILD | WS_BORDER,100,100,300,50,hWnd,(HMENU)17,0,0);

    ShowWindow( hWnd,SW_SHOWDEFAULT );

    MSG msg;
    ZeroMemory( &msg,sizeof( msg ) );
    while( msg.message != WM_QUIT )
    {
        if( PeekMessage( &msg,NULL,0,0,PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }

    UnregisterClass( L"My Window",wc.hInstance );
    return 0;
}

【问题讨论】:

  • editHWND 是在哪里创建的?当你的窗口得到WM_CREATE时它真的存在吗?
  • 就在创建主窗口 hWnd 的位置下方。我想是的。
  • WM_CREATE 在对CreateWindowEx 的调用返回之前被调用,所以我想你会发现,当你试图对窗口进行子类化时,它实际上还没有被创建.
  • 您承认您没有进行任何错误检查,但是当您试图找出某些原因无法正常工作时,检查错误通常可以为您提供线索错了。
  • @jamesdlin 好点,我可能应该包括错误检查,但我不希望代码看起来过于复杂或太长。 JonathanPotter 非常感谢你,它现在工作正常,我没有意识到这一点。另一个快速的问题,当按下返回键时,我使用 WM_SETTEXT 清除缓冲区,但是 Windows 仍然处理返回键并且我在机器上收到哔哔声,因为它无法创建新行(如果它设置为 ES_MULTILINE 一个新的行已创建。)如何停止窗口处理返回键,使输入保持空白?谢谢

标签: c++ winapi controls subclassing


【解决方案1】:

MsgProc() 是“我的窗口”窗口的窗口过程。当您处理WM_CREATE 消息时,您正在处理该窗口的创建,在调用第二个CreateWindow() 以创建编辑窗口之前。

更糟糕的是,即使您正确地对编辑窗口进行了子类化,您也会在设置后立即删除子类。所以EditSubClassProc() 无论如何都不会调用任何更改。

由于您在创建编辑窗口时没有为它定义自定义窗口过程,因此您不能使用WM_CREATE 消息来子类化编辑窗口(除非您使用消息挂钩,这在这情况)。只需在CreateWindow() 退出后调用SetWindowLong()

试试这个:

#include <Windows.h>
#include <wchar.h>

HWND editHWND = NULL;
WNDPROC wpOrigEditProc = NULL;

LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_CHAR)
    {
        //do my stuff
    }
    return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_CLOSE:
        DestroyWindow(hWnd);
        return 0;

    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

int WINAPI wWinMain( HINSTANCE hInst,HINSTANCE,LPWSTR,INT )
{
    WNDCLASSEX wc = { sizeof( WNDCLASSEX ),CS_CLASSDC,MsgProc,0,0,
                      GetModuleHandle( NULL ),NULL,NULL,NULL,NULL,
                      TEXT("My Window"),NULL };
    RegisterClassEx( &wc );

    HWND hWnd = CreateWindowW( TEXT("My Window"),TEXT("test application"),
                              WS_OVERLAPPEDWINDOW,100,100,800,600,
                              NULL,NULL,wc.hInstance,NULL );

    editHWND = CreateWindow( TEXT("edit"),TEXT("hi there"),WS_VISIBLE | WS_CHILD | WS_BORDER,100,100,300,50,hWnd,(HMENU)17,0,0);

    wpOrigEditProc = (WNDPROC) SetWindowLongPtr(editHWND, GWL_WNDPROC, (LONG_PTR) EditSubclassProc);

    ShowWindow( hWnd, SW_SHOWDEFAULT );

    MSG msg;
    while ( GetMessage( &msg,NULL,0,0 ) > 0 )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    UnregisterClass( TEXT("My Window"),wc.hInstance );
    return 0;
}

话虽如此,对窗口进行子类化的另一种方法是改用SetWindowSubclass()

#include <Windows.h>
#include <wchar.h>

HWND editHWND = NULL;

LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    if (uMsg == WM_CHAR)
    {
        //do my stuff
    }

    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_CLOSE:
        DestroyWindow(hWnd);
        return 0;

    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

int WINAPI wWinMain( HINSTANCE hInst,HINSTANCE,LPWSTR,INT )
{
    WNDCLASSEX wc = { sizeof( WNDCLASSEX ),CS_CLASSDC,MsgProc,0,0,
                      GetModuleHandle( NULL ),NULL,NULL,NULL,NULL,
                      TEXT("My Window"),NULL };
    RegisterClassEx( &wc );

    HWND hWnd = CreateWindowW( TEXT("My Window"),TEXT("test application"),
                              WS_OVERLAPPEDWINDOW,100,100,800,600,
                              NULL,NULL,wc.hInstance,NULL );

    editHWND = CreateWindow( TEXT("edit"),TEXT("hi there"),WS_VISIBLE | WS_CHILD | WS_BORDER,100,100,300,50,hWnd,(HMENU)17,0,0);

    SetWindowSubclass(editWND, EditSubclassProc, 0, 0);

    ShowWindow( hWnd, SW_SHOWDEFAULT );

    MSG msg;
    while ( GetMessage( &msg,NULL,0,0 ) > 0 )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    UnregisterClass( TEXT("My Window"),wc.hInstance );
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    • 2023-02-16
    • 2012-08-31
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多