通过控件子类化实现Edit Control接收Enter按键

众所周知,Win SDK的标准Edit控件要接收Enter键只能在样式里增加一个“多行”,如果保持单行还想接收Enter键呢?

MSDN指出了3个方法:
1是在父窗口的WM_COMMAND中处理。2是通过为控件注册回调函数实现。3是通过MFC类重载函数实现。
第1个方法我试了不知道为什么拦截不到Enter按键。
第2个方法在StackoverFlow上有解决方案:

WNDPROC oldEditProc;

LRESULT CALLBACK subEditProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch (msg)
   {
    case WM_KEYDOWN:
         switch (wParam)
         {
          case VK_RETURN:
          //Do your stuff
              break;  //or return 0; if you don't want to pass it further to def proc
          //If not your key, skip to default:
         }
    default:
         return CallWindowProc(oldEditProc, wnd, msg, wParam, lParam);
   }
   return 0;
}

void somecreateeditproc()
{
  HWND hInput = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", 
    WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL, 
    0, 0, 100, 100, hwnd, (HMENU)IDC_MAIN_INPUT, GetModuleHandle(NULL), NULL);

  oldEditProc = (WNDPROC)SetWindowLongPtr(hInput, GWLP_WNDPROC, (LONG_PTR)subEditProc);
}

这个是可以达到效果的。

之后我尝试了控件子类化:
TEdit.h:

#pragma once
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>

class TEdit
{
protected:
    static WNDPROC oldEditProc;
    static LRESULT CALLBACK subEditProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam); 
    void TEdit::CreateEx(DWORD dwExStyle, LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,int x, int y, int nWidth, int nHeight, HWND hParent,HMENU hMenu, HINSTANCE hInst);

    virtual LRESULT TEdit::WndProc(WNDPROC wndproc, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    //接收VK_RETURN,VK_ESCAPE,返回值决定是否调用默认消息处理
    virtual bool TEdit::OnKeyDown(WPARAM wParam, LPARAM lParam);

    //接收字符按键,返回值决定是否调用默认消息处理
    virtual bool TEdit::OnChar(WPARAM wParam, LPARAM lParam);
public:
    HWND m_hWnd;
    HINSTANCE m_hInst;
    TEdit();
    ~TEdit();
    void TEdit::CreateEditEx(HWND hParent, UINT id, HINSTANCE hInst);//创建Edit
    void TEdit::SetPos(int x, int y, int width, int height);//设置大小及位置
    void TEdit::ShowWindow(bool bShow);//设置可见性
    void CDECL TEdit::SetText(TCHAR szFormat[], ...);//设置内容
    int TEdit::GetLength();//获取字符串长度
    void TEdit::SetSelect(int iStart, int iEnd);//选择
    void TEdit::SetSelectAll();//全选
};

TEdit.cpp:

#include "TEdit.h"


TEdit::TEdit()
{
    m_hWnd = NULL;
    m_hInst = NULL;
}


TEdit::~TEdit()
{
}

WNDPROC TEdit::oldEditProc;
LRESULT CALLBACK TEdit::subEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    TEdit * pEdit;
    pEdit=(TEdit *)GetWindowLong(hWnd, GWL_USERDATA);
    if (pEdit)
        return pEdit->WndProc(oldEditProc,hWnd, uMsg, wParam, lParam);
    else
        return CallWindowProc(oldEditProc, hWnd, uMsg, wParam, lParam);
}

LRESULT TEdit::WndProc(WNDPROC wndproc,HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CHAR:
        if (OnChar(wParam, lParam))
            return CallWindowProc(wndproc, hWnd, uMsg, wParam, lParam);
        else
            return 0;
    case WM_KEYDOWN:
        if (OnKeyDown(wParam, lParam))
            return CallWindowProc(wndproc, hWnd, uMsg, wParam, lParam);
        else
            return 0;
    }
    return CallWindowProc(wndproc, hWnd, uMsg, wParam, lParam);
}

void TEdit::CreateEx(DWORD dwExStyle, LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,
    int x, int y, int nWidth, int nHeight, HWND hParent,
    HMENU hMenu, HINSTANCE hInst)
{
    m_hInst = hInst;
    m_hWnd = CreateWindowEx(dwExStyle, lpszClass,
        lpszName, dwStyle, x, y, nWidth, nHeight,
        hParent, hMenu, hInst, 0);
}

void TEdit::CreateEditEx(HWND hParent,UINT id,HINSTANCE hInst)
{
    m_hInst = hInst;
    TEdit::CreateEx(WS_EX_CLIENTEDGE,
        TEXT("Edit"), 0,
        WS_CHILD,// | ES_AUTOHSCROLL | WS_VISIBLE
        0, 0, 0, 0, hParent,(HMENU)id, hInst);
    SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);

    oldEditProc = (WNDPROC)::SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)subEditProc);
}

void TEdit::SetPos(int x, int y, int width, int height)
{
    ::SetWindowPos(m_hWnd, HWND_TOP, x,y,width,height,0);//SWP_SHOWWINDOW
}

void TEdit::ShowWindow(bool bShow)
{
    ::ShowWindow(m_hWnd, bShow ? SW_SHOWNORMAL : SW_HIDE);
}

bool TEdit::OnKeyDown(WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
    case VK_ESCAPE:
    case VK_SPACE:
    case VK_RETURN:
        SetWindowText(this->m_hWnd, TEXT("no"));
        return false;//若是这3个键按下则修改TEXT为“no”,并且吞掉空格键
    }
    return true;
}

bool TEdit::OnChar(WPARAM wParam, LPARAM lParam)
{
    return false;//截掉所有输入
}

int TEdit::GetLength()
{
    return ::GetWindowTextLength(m_hWnd);
}

void TEdit::SetSelect(int iStart, int iEnd)
{
    SendMessage(m_hWnd, EM_SETSEL, iStart, iEnd);
}

void TEdit::SetSelectAll()
{
    SetSelect(0, GetLength());
}

void CDECL TEdit::SetText(TCHAR szFormat[], ...)
{
    TCHAR szBuffer[1024];
    va_list pArgList;
    va_start(pArgList, szFormat);
    _vsntprintf(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), szFormat, pArgList);
    va_end(pArgList);

    SetWindowText(m_hWnd, szBuffer);
}

使用示例:

    TEdit edit;
    edit.CreateEditEx(hWnd, IDR_LINEEDIT, m_hInst);
    edit.SetPos(0, 0, 40, 20);
    edit.ShowWindow(true);
    edit.UpdateWindow();

hWnd为edit的父窗口句柄。修改TEdit.cpp中的OnChar和OnKeyDown函数即可拦截Edit Control的所有按键。也可创建一个TEdit的子类,重载OnChar和OnKeyDown函数。
在两个函数中根据输入情况得出不同的返回值,可以决定Edit是否调用默认消息处理。

参考文献
How To Use the ENTER Key from Edit Controls in a Dialog Box
https://support.microsoft.com/en-us/kb/102589
Edit control capture enter key
http://stackoverflow.com/questions/15711311/edit-control-capture-enter-key
WM_CHAR、WM_KEYDOWN和WM_SYSKEYDOWN消息
http://blog.csdn.net/xiexievv/article/details/6313911

猜你喜欢

转载自blog.csdn.net/tomwillow/article/details/52972111