我尝试对 CButton 进行子类化有什么问题?
What's wrong with my attempt at subclassing CButton?
我第一次尝试创建一个子类控件,但我觉得我做错了什么。控件是一个Button,我将其放置在设计器中。这是它的类:
class TTTField : public CButton
{
public:
BEGIN_MSG_MAP_EX(TTTField)
MSG_WM_INITDIALOG(OnInitDialog);
END_MSG_MAP()
TTTField operator=(const CWindow& btn);
private:
const BOOL OnInitDialog(const CWindow wndFocus, const LPARAM lInitParam);
};
目前还没有什么特别的。
然而,我不能真正实现在这个控件中接收windows消息。这很糟糕,考虑到尝试子类化控件的主要原因是,这应该是一个具有可重用、自定义Paint行为的可重用类。我想覆盖某些消息处理程序,同时保留那些我没有显式请求的通常的CButton例程。
正如您所看到的,我实现了一个消息映射,但是消息没有传入。
我是这样设置这个类的实例的:
TTTField fld;
是我的主对话框类的成员变量。在这个类中,我添加了以下DDX_MAP:
BEGIN_DDX_MAP(TTTMainDialog)
DDX_CONTROL_HANDLE(IDC_BTN, fld)
END_DDX_MAP()
IDC_BTN为设计器上按钮的id。
在TTTField的赋值操作符重载中,我有以下内容:
TTTField TTTField::operator=(const CWindow& btn)
{
Attach(btn);
return *this;
}
我觉得这个操作符过载可能是我的问题的根源,但是我就是找不到一个网站,它可以正确地解释整个主题,而不使用看起来过时了20年的代码。
我在这里做错了什么?我现在真的很迷茫。
按钮类应该定义如下:
class TTTField : public CWindowImpl<TTTField, CButton>
{
protected:
BEGIN_MSG_MAP_EX(TTTField)
MSG_WM_LBUTTONDOWN(OnLButtonDown)
END_MSG_MAP()
protected:
LRESULT OnLButtonDown(UINT, CPoint)
{
//Edit: this override is meant for testing the subclass only
//it's insufficient for handling button clicks
MessageBox(L"Testing override...");
return 0;
}
};
覆盖对话框的OnInitDialog
,调用SubclassWindow
子类化按钮:
class TTTMainDialog: public CDialogImpl<CMainDialog>
{
public:
enum { IDD = IDD_MYDIALOG };
BEGIN_MSG_MAP(TTTMainDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
END_MSG_MAP()
TTTField fld;
LRESULT OnInitDialog(UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
fld.SubclassWindow(GetDlgItem(IDC_BTN));
return 0;
}
};
编辑,用于初始化
class TTTField : public CWindowImpl<TTTField , CButton>
{
public:
void Create(CWindow *wnd, int id)
{
SubclassWindow(wnd->GetDlgItem(id));
//add initialization here
}
...
}
然后创建按钮:
//fld.SubclassWindow(GetDlgItem(IDC_BTN));
fld.Create(this, IDC_BTN); //<== use this instead
也许对按钮进行子类化的最好的例子,或者至少是其中之一,就在WTL的源代码中,在atlctrlx.h:
的顶部。template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
{
public:
DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
...
你也将文件外部资源在这个类:使用WTL的CBitmapButton。
这还没有提到WTL关于做控件的评论:
// These are wrapper classes for Windows standard and common controls.
// To implement a window based on a control, use following:
// Example: Implementing a window based on a list box
//
// class CMyListBox : CWindowImpl<CMyListBox, CListBox>
// {
// public:
// BEGIN_MSG_MAP(CMyListBox)
// // put your message handler entries here
// END_MSG_MAP()
// };
更多简单和复杂的自定义WTL控件的示例可以在vikso .dk找到。
关于WTL控件扩展的一个令人困惑的事情是,像CButton
, CComboBox
这样的基本类是标准控件的薄包装。它们主要将方法转换为要发送的消息。通常可以很容易地将这些类的实例强制转换为HWND
并返回。
标准控件本身通过支持通知消息提供一定程度的自定义。
当你子类化一个控件时,你是在你的一侧添加功能,以某种方式需要与现有实现互操作,并且控件类不再是薄包装器。因此,您直接继承CWindowImpl
而不是CButton
。下一个挑战是具体子类化:您需要创建原始窗口,之后,使用HWND
句柄,修改它以通过消息映射路由消息。这就是需要SubclassWindow
方法的地方。也就是说,你有控件创建,你查找它的句柄,例如与GetDlgItem
,然后你子类化的窗口使用你的类实例SubclassWindow
调用。或者,您也可以使用新的类Create
方法创建控件,在这种情况下,CreateWindow
和与消息映射的关联将为您完成。
一些更复杂的自定义控件的实现还需要您将来自父窗口的通知消息反映到控件中,以便它们可以在相同的自定义控件类中处理它们。这通常需要您在对话框类消息映射中添加一行REFLECT_NOTIFICATIONS
(请参阅此相关问题)。
- 警告处理为错误这里有什么问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 当我尝试添加 2 个大字符串时,我无法弄清楚出了什么问题
- 违反const正确性:我应该现实地期待什么问题
- 这个带有模板<类 Vector 的C++代码片段有什么问题>
- 我的逻辑反转字符串中的元音有什么问题?
- 需要以下代码的帮助,下面的代码有什么问题
- 常量公共成员有什么问题?
- 以下代码中的函数模板有什么问题?
- 这个返回元素位置的基于循环的函数有什么问题?
- creat_list2功能有什么问题?
- 格式说明符C++有什么问题
- 任何人都可以告诉我我的 C++ 代码出了什么问题?
- 从 argv[1] 转换为字符 * 字符串后有什么问题?
- 我的堆栈和库存清单程序的结构有什么问题?
- 此工厂功能有什么问题?
- 以下 C++ 代码有什么问题?
- 数组为此合并排序函数提供了正确的输出,但向量给出了不正确的输出.出了什么问题?
- reinterpret_cast,只读访问,简单的可复制类型,会出什么问题?
- 它解决了什么问题,对于非真空初始化,生命周期在初始化之前就开始了