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 に答える