Subclass 使用 SetWindowSubclass 自定义 class 中的按钮
Subclass a button within a custom class using SetWindowSubclass
我正在尝试编写一个 class 来处理按钮的创建及其内部消息。我希望保留 class 本身包含的所有代码。这可能很简单或不可能,因为我对 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.
}
}
这会引发错误:
argument of type "LRESULT (__stdcall button::*)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)" is incompatible with parameter of type "SUBCLASSPROC"
我希望有人可以解释一个简单的解决方案,或者建议 Winapi 中的替代方案,因为我希望学习本机 windows 和 C++,而不是依赖其他库。
您正在尝试使用 非静态 class 方法 作为子class 回调。那是行不通的,因为非静态 class 方法有一个 API 无法传递的隐藏 this
参数。
要执行您正在尝试的操作,您必须删除 this
参数(您可以使用 SetWindowSubclass()
的 dwRefData
参数代替),方法是:
使用静态class方法:
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.
}
使用 非成员函数:
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;
}
我正在尝试编写一个 class 来处理按钮的创建及其内部消息。我希望保留 class 本身包含的所有代码。这可能很简单或不可能,因为我对 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.
}
}
这会引发错误:
argument of type "LRESULT (__stdcall button::*)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)" is incompatible with parameter of type "SUBCLASSPROC"
我希望有人可以解释一个简单的解决方案,或者建议 Winapi 中的替代方案,因为我希望学习本机 windows 和 C++,而不是依赖其他库。
您正在尝试使用 非静态 class 方法 作为子class 回调。那是行不通的,因为非静态 class 方法有一个 API 无法传递的隐藏 this
参数。
要执行您正在尝试的操作,您必须删除 this
参数(您可以使用 SetWindowSubclass()
的 dwRefData
参数代替),方法是:
使用静态class方法:
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. }
使用 非成员函数:
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; }