【问题标题】:Subclass a button within a custom class using SetWindowSubclass [duplicate]使用 SetWindowSubclass 在自定义类中子类化按钮 [重复]
【发布时间】:2016-11-26 21:52:34
【问题描述】:

我正在尝试编写一个类来处理按钮的创建及其内部消息。我希望将所有代码保留在类本身中。这可能很简单或不可能,因为我对 Winapi 和 C++ 比较陌生,更广泛地使用了 vb.net。我找不到完成这种看似简单的转换的示例。我确实找到了建议我使用备用 API 或使用 SetWindowLongPtr 的示例,有人告诉我 SetWindowSubclass 是更好的选择。我尝试的代码如下:

#pragma once
#include <iostream>
#include <Windows.h>
#include <Commctrl.h>

using namespace std;

    class button {
    public:
        bool initialize();
        buttton(int x, int y, int length, int width, LPCWSTR text, HWND parent, HINSTANCE hInstance);  // This is the constructor

    private:
        LPCWSTR text = L"Button";
        int height = 25;
        int width = 100;
        int x = 0;
        int y = 0;
        HWND parent;
        HWND thisHandle;
        HINSTANCE thisInstance;
        bool initialized = false;
        LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

    };


    button::button(int x, int y, int height, int width, LPCWSTR text, HWND parent, HINSTANCE hInstance) {
        this->x = x;
        this->y = y;
        this->height = height;
        this->width = width;
        this->text = text;
        this->parent = parent;
        thisInstance = hInstance;
    }
        bool button::initialize()
    {
        thisHandle = CreateWindowW(
            L"BUTTON",  // Predefined class; Unicode assumed 
            text,      // Button text 
            WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS | BS_NOTIFY,  // Styles 
            x,         // x position 
            y,         // y position 
            width,        // Button width
            height,        // Button height
            parent,     // Parent window
            NULL,       // No ID.
            thisInstance,
            NULL);      // Pointer not needed.
        if (!thisHandle)
        {
            return false;
        }
        initialized = true;
        //Problem Code****
        SetWindowSubclass(thisHandle, mySubClassProc, 1, 0);
        //****  
        return true;
    }

    LRESULT CALLBACK button::mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {

        //Code handling messages here.
    }
}

这会引发错误:

“LRESULT (__stdcall button::*)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)”类型的参数与“SUBCLASSPROC”类型的参数不兼容

我希望有人可以解释一个简单的解决方案,或者在 Winapi 中提出一个替代方案,因为我希望学习本机 Windows 和 C++,而不是依赖其他库。

【问题讨论】:

  • 你还有很多事情要了解 C 和 C++ 之间的差异,子类化也不足以正确地做到这一点。请避免重新发明这个轮子,winapi 有许多优秀的 C++ 包装器。从 MFC、Qt、wxwidgets 中挑选。如果您不想使用它们,那么至少看看它们的作用。
  • 声明你的子类过程为static...
  • @Hans Passant:我确实有很多东西要学。此特定代码并非旨在用于最终产品,而是试图探索可能性。虽然“重新发明轮子”似乎毫无意义,但我认为使用上述包装器不会让我更好地理解 Winapi 的内部工作原理。如果子类化不足以正确地做到这一点,你能建议我应该学习什么来在本地 Winapi 中完成类似的事情吗?此外,我将研究建议的包装器。

标签: c++ winapi subclassing


【解决方案1】:

您正在尝试使用非静态类方法作为子类回调。这是行不通的,因为非静态类方法有一个隐藏的this 参数,API 将无法传递该参数。

要执行您正在尝试的操作,您必须删除this 参数(您可以改用SetWindowSubclass()dwRefData 参数),方法是:

  1. 使用静态类方法

    class button {
    public:
        bool initialize();
        ...
    
    private:
        ...
    
        static LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
    
    };
    
    bool button::initialize()
    {
        ...
        SetWindowSubclass(thisHandle, mySubClassProc, 1, (DWORD_PTR) this);
        return true;
    }
    
    LRESULT CALLBACK button::mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        button *pThis = (button*) dwRefData;
    
        //Code handling messages here.
    }
    
  2. 使用非成员函数

    class button {
    public:
        bool initialize();
        ...
    };
    
    LRESULT CALLBACK myButtonSubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        button *pBtn = (button*) dwRefData;
        //Code handling messages here.
    }
    
    bool button::initialize()
    {
        ...
        SetWindowSubclass(thisHandle, myButtonSubClassProc, 1, (DWORD_PTR) this);
        return true;
    }
    

【讨论】:

    猜你喜欢
    • 2017-08-08
    • 1970-01-01
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多