2

我将自定义窗口封装在一个带有静态 WndProc 函数的类中,以处理由它生成的消息。现在我有一个子类,它在消息处理过程中实现了一些与父类不同的特性。

例如在下面的代码中,子类中 WM_LBUTTONDOWN 中发生的情况与父类中发生的情况不同。

我考虑过多态性,但我认为它不起作用,因为从父类调用 ::SetWindowLongPtr() 并且传递给的“this”指针属于父类,如果我错了,请纠正我。

如果我错了,多态性在这种情况下也会起作用,那么也有一些消息不是由父类处理的,应该在子类中处理,并在父类中放置一个空的虚函数只是为了不看起来很干净,除了很难为窗口产生的每条消息放置一个空的虚拟函数,只是为了将来是否会使用它。

将有几个这样的子类,每个子类对某些消息的行为不同,但不是全部。

那么,我该怎么做呢。

父级.cpp

parent::parent()
{

    WNDCLASSEX wincl;

    wincl.hInstance         = hInstance;
    wincl.lpszClassName     = "parent";
    wincl.lpfnWndProc       = WndProc;
    wincl.style             = CS_BYTEALIGNWINDOW;
    wincl.cbSize            = sizeof (WNDCLASSEX);
    wincl.hIcon             = 0;
    wincl.hIconSm           = 0;
    wincl.hCursor           = ::LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName      = NULL;
    wincl.cbClsExtra        = 0;
    wincl.cbWndExtra        = 4;
    wincl.hbrBackground     = ::CreateSolidBrush( backgroundColor );

    ::RegisterClassEx ( &wincl );

    hwnd = ::CreateWindowEx ( 0, "parent", txt.c_str(), WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, 0 ) ;

    ::SetWindowLongPtr( hwnd , GWLP_USERDATA , ( LONG ) this ) ;

}



LRESULT CALLBACK parent::WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{


   view::parent* panel = reinterpret_cast < view::parent* > (  ::GetWindowLongPtr ( hwnd , GWLP_USERDATA )  );


   switch (message)
   {    


      case WM_CREATE:

          ::SendMessage ( hwnd, WM_SETFONT, ( WPARAM ) panel->hFont, ( LPARAM ) true );

          break ;



      case WM_COMMAND:


          return panel->command ( message, wParam, lParam );

          break ;



      case WM_LBUTTONDOWN:


          return panel->lButton ( message, wParam, lParam );

          break;



      case WM_RBUTTONDOWN:


          return panel->rButton ( message, wParam, lParam );

          break;



      case WM_ERASEBKGND:


          return 1;

          break;



      case WM_PAINT:


          return panel->paint ( );


          break ;



      default:


         return ::DefWindowProc (hwnd, message, wParam, lParam);


   }

    return 0 ;


};

谢谢。

4

1 回答 1

2

尝试这样的事情:

class parent
{
private:
    // ...
    static LRESULT CALLBACK WndProcCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
protected:
    HWND m_hwnd;
    // ...
    virtual LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);
    virtual LRESULT DefWndProc(UINT message, WPARAM wParam, LPARAM lParam);
    virtual LRESULT command(WPARAM wParam, LPARAM lParam);
    virtual LRESULT lButtonDown(WPARAM wParam, LPARAM lParam);
    virtual LRESULT rButtonDown(WPARAM wParam, LPARAM lParam);
    virtual LRESULT paint();
    // ...
public:
    parent();
    virtual ~parent();
    // ...
};

parent::parent()
{
    WNDCLASSEX wincl = {0};

    wincl.hInstance         = hInstance;
    wincl.lpszClassName     = "parent";
    wincl.lpfnWndProc       = WndProcCallback;
    wincl.style             = CS_BYTEALIGNWINDOW;
    wincl.cbSize            = sizeof(WNDCLASSEX);
    wincl.hIcon             = 0;
    wincl.hIconSm           = 0;
    wincl.hCursor           = ::LoadCursor(NULL, IDC_ARROW);
    wincl.lpszMenuName      = NULL;
    wincl.cbClsExtra        = 0;
    wincl.cbWndExtra        = 4;
    wincl.hbrBackground     = ::CreateSolidBrush(backgroundColor);

    ::RegisterClassEx(&wincl);

    m_hwnd = NULL;
    ::CreateWindowEx(0, "parent", txt.c_str(), WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, this);
}

parent::~parent()
{
    if (m_hwnd)
        DestroyWindow(m_hwnd);
}

LRESULT CALLBACK parent::WndProcCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    parent* panel;

    if (message == WM_CREATE)
    {
        CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT*>(lParam);
        panel = static_cast<parent*>(cs->lpCreateParams);
        panel->m_hwnd = hwnd;
        ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(panel));
    }
    else
       panel = reinterpret_cast<parent*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));

    if (panel)
        return panel->WndProc(message, wParam, lParam);

    return ::DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT parent::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
   switch (message)
   {    
      case WM_CREATE:
          ::SendMessage(m_hwnd, WM_SETFONT, (WPARAM) hFont, TRUE);
          break ;

      case WM_COMMAND:
          return command(wParam, lParam);
          break ;

      case WM_LBUTTONDOWN:
          return lButtonDown(wParam, lParam);
          break;

      case WM_RBUTTONDOWN:
          return rButtonDown(wParam, lParam);
          break;

      case WM_ERASEBKGND:
          return 1;
          break;

      case WM_PAINT:
          return paint();
          break;
    }

    return DefWndProc(message, wParam, lParam);
}

LRESULT parent::DefWndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    return ::DefWindowProc(m_hwnd, message, wParam, lParam);
}

LRESULT parent::command(WPARAM wParam, LPARAM lParam)
{
    return DefWndProc(WM_COMMAND, wParam, lParam);
}

LRESULT parent::lButtonDown(WPARAM wParam, LPARAM lParam)
{
    return DefWndProc(WM_LBUTTONDOWN, wParam, lParam);
}

LRESULT parent::rButtonDown(WPARAM wParam, LPARAM lParam)
{
    return DefWndProc(WM_RBUTTONDOWN, wParam, lParam);
}

LRESULT parent::paint()
{
    return 0;
}

这不仅包含多态性和封装,而且使WndProc()自己成为虚拟允许派生类覆盖任何接收到的消息的行为(好吧,之后接收到的任何消息WM_CREATE都是),尤其是parent没有以下概念的消息:

class child : public parent
{
protected:
    LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);
};

LRESULT child::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_SOMETHING)
    {
        // ...
        return 0;
    }

    return parent::WndProc(message, wParam, lParam);
}
于 2013-07-07T19:22:55.570 回答