【问题标题】:Having trouble when trying to implement a Event Handler for Windows API wrapper尝试为 Windows API 包装器实现事件处理程序时遇到问题
【发布时间】:2012-11-18 17:26:41
【问题描述】:

朋友们,我正在尝试实现 Windows API 的封装,我想从父窗口捕获子窗口事件,所以我做了一个简单的事件处理程序。我使用函数指针来存储回调函数。我用静态函数做到了。请参阅下面的代码。

class Widget;
typedef void (*EventProc)(MSG* EventArgs);
class Widget
{
public:
    /// Constructors destructor and methods for Registering and Creating Windows
    static LRESULT CALLBACK MainProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
    {
        MSG struct_msg;
        struct_msg.hWnd=hWnd;
        struct_msg.message=msg;
        struct_msg.wParam=wParam;
        struct_msg.lParam=lParam;

        Widget* wid=(Widget*)GetWidgetPointerFromHWND(hWnd);

        switch(msg)
        {
            case WM_CREATE:
                if(Created!=NULL)
                    (*(wid->Created))(&struct_msg);break;
            case WM_DESTROY:
                if(Destroyed!=NULL)
                    (*(wid->Destroyed))(&struct_msg);break;
            default:
                return DefWindowProc(hWnd,msg,wParam,lParam);
        }
        return 0;
    }
    EventProc Created;
    EventProc Destroyed;

};

class CustomControl: public Widget
{
    /// Constructor destructor and other methods

};

class Window: public Widget
{
public:

    static void ChildCreated(Widget* Sender,Widget* Self,MSG* EventArgs)
    {
        MessageBox(0,0,0,0);
    }

    Window()
    {
        control1=new CustomControl(100,100,200,200); //left,top,width,height
        this->AddChild(control1);
        control1->Created = ChildCreated; 
    }
private:
    CustomControl control1;
};

这可行,但由于静态函数没有 this 指针,我无法访问 类窗口 中的变量和成员函数。 我想制作一个成员函数作为回调函数(事件处理程序)。 我希望你明白我要解决的问题。请帮帮我。

【问题讨论】:

  • 如果你从GetWidgetPointerFromHWND 得到Widget 的实例,你可以访问它的变量和成员。那么有什么问题呢?
  • @Lol4t0 我想将 Window 的非静态成员函数作为事件处理程序。
  • 但是只要你得到wid,你就可以像wid->handleEvent(msg, wParam, lParam)一样调用它的函数。对吗?
  • 看看另一个 GUI 框架的实现,看看他们是如何做到的。
  • 好的,我的疑问是如何将非静态成员函数作为事件处理程序并通过其指针从基类调用它。不仅仅是这个例子@

标签: c++ winapi function pointers casting


【解决方案1】:

您在此示例中展示的主要思想是正确的。

您制作了一些 static WndProc 函数和映射,将 HWND 映射到您的类。

创建小部件的新实例时,将其添加到映射中。在销毁时,您将其从映射中删除。

在您的 WndProc 函数中,您从映射中获取类的实例并调用该实例的虚拟事件处理程序函数:

class WidgetBase
{
public:
    WidgetBase()
    {
        _handle = CreateWindow(/*...*/, &WidgetBase::MainProc, /*...*/);
        _widgets.insert(std::make_pair(handle, this);
    }
    virtual ~WidgetsBase() 
    {
       _widgets.remove(handle);
    }
protected:
    HWND _handle;
    virtual LRESULT handleEvents(UINT msg,WPARAM wParam,LPARAM lParam)
    {
         return DefWindowProc(_handle, hWnd,msg,wParam,lParam);
    }
private:
    static std::map<HWND, WidgetBase*> _widgets;

    static WidgetBase* GetWidgetPointerFromHWND(HWND handle)
    {
        // some error handling should be put there
        return _widgets[handle];
    }

    static LRESULT CALLBACK MainProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
    {
        WidgetBase* wid=GetWidgetPointerFromHWND(hWnd);
        if (wid) {
            return wid->handleEvents(msg, wParam, lParam);
        }
        else {
            return DefWindowProc(hWnd,msg,wParam,lParam);
        }
    }
};
std::map<HWND, WidgetBase*> WidgetBase::_widgets;

那么在你的派生类中你只需要重写handleEvents函数:

class Derived: public WidgetBase
{
protected:
virtual LRESULT handleEvents(UINT msg,WPARAM wParam,LPARAM lParam)
    {
         // This is your event handler, that is memeber function
         //...
         return WidgetBase::handleEvents(msg, wParam, lParam);
    }
};

【讨论】:

    猜你喜欢
    • 2012-05-14
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 2019-10-23
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    • 2020-06-28
    相关资源
    最近更新 更多