Windows自带控件的样式太过单调,为了界面美观一些很多时候需要自己绘制,譬如 按钮,编辑框,组合框等。
自己总结过程如下:
1.生成一个以要重绘的空间类为基类的派生类。(我想重绘CButton, 则应该生成一个CMyButton : public CButton。
2.在派生类里面重载DrawItem虚函数(如果该类中没有DrawItem需函数,可以加入WM_NCPAINT消息来代替,在消息的执行体内绘制)
DrawItem虚函数是一个专门用来重绘自画空间的函数,且该函数只能用在派生类中!我们可以重写函数体,在里面完成对控件的定制绘制。
DrawItem函数的调用要求控件的属性是" Owner Draw", 我们当然可以在资源对话框的属性里面设置空件为"OwnerDraw"属性,但更好的方法是在PreSubclassWindow()中进行。注意:不要和PreCreateWindow()函数混了,后者中执行ModifyStyle()函数不起效果。
当CWnd::Create()或DDX_Control被调用后,这两个函数都会调用SubClassWindow(), SubClassWindow()紧接着会调用PreSubclassWindow(),我们可以在该函数内设置控件的属性为"OwnerDraw"
void CMyButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW); // make the button owner drawn这个很重要,否则不能重绘
}
3.子类化重绘类。
有三种方法都可以实现子类化,主要是:
(1)在创建过程中用DDX子类化一个类。
具体就是在ClassWizard里为对应的对话框内的CButton创建一个类型为CMyButton的变量。
CMyButton m_myButton;
这样, 对话框的DoDataExchange会创建一个DDX_Control调用。DDX_Control会调用SubClassWindow, 这样就可以使得你的按钮实用CMyButton的消息处理,而不用CButton的。
(2)实用一个不被ClassWizard支持的类子类化一个控件。
假如你的项目中已经加入了一个窗口类,你想子类化该类类型的一个对象,但是ClassWizard并不提供给你这种类类型,这时你就需要重建ClassWizard文件。
首先备份以下项目下的.clw文件到一个别的目录下,然后删除项目目录下的.clw文件,然后点击Ctrl+W,这时会弹出一个对话框让你选择你想包含的类。如果没有选择你的新类,你可以自己到头文件里手动修改父类为子类(譬如把CButton 修改为CMyButton)
(3)子类化一个已经存在的窗口类。
用DDX子类化一个类非常简单,但如果我们想子类化的是一个已经存在的类的时候,这种方法就不适合了。例如我们想子类化一个组合框内的编辑框控件,则你需要事先把组合框创建好。
这种情况下,你可以使用方便的SubclassDlgItem()或SubclassWindow()函数来完成。这两个函数允许你动态的子类化一个类, 也就是他们可以使你的的新类类型的对象依附于一个已经存在的窗口。
例如假设我们有一个对话框,上面有一个ID为ID_BUTTON1的按钮控件,这个控件早已经创建成功存在于对话框了,而我们想把这个按钮跟一个CMyButton类的对象建立联系,从而使得这个按钮控件表现出CMyButton定义的行为。
(a)首先我们需要定义一个CMyButton类的对象,这个对象定义为对话框或者视图类(View)的变量就比较合适。
CMyButton m_btnButton;
定义好变量后, 我们可以在对话框的OnInitialDialog()(或者别的合适的地方也可以)调用:
m_btnButton.SubclassDlgItem(IDC_BUTTON1, this);
完成子类化。
(b)如果你不想使用SubclassDlgItem,也可以这样子类化。假设你已经获得了一个指向我们想子类化控件类的指针(譬如这里就是一个指向IDC_BUTTON1所标识的按钮的指针),如果你是在视图类(View)或者别的从CWnd继承来的类里面来完成控件的动态创建,你可以这样:
CWnd* pWnd = GetDlgItem(IDC_BUTTON1); // or use some other method to get
// a pointer to the window you wish
// to subclass
ASSERT( pWnd && pWnd->GetSafeHwnd() );
m_btnMyButton.SubclassWindow(pWnd->GetSafeHwnd());
完成子类化过程。
要在按钮中进行了画图的话,,在窗口进行了刷新操作的话,需要在DrawItem函数中添加if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE)。。。这是判断是否为刷新的条件语句。
总上,子类化并不难,你只需要认真的选择你需要子类化的类,并且清楚你想自己处理的消息是什么并处理他们。清楚你要子类化的类都有哪些虚拟函数并重写他们。