r2 - 17 Jun 2010 - 13:23:01 - SizheTanYou are here: TWiki >  Products Web > MStudioMGNCSV1dot0PG > MStudioMGNCSV1dot0PGP3C3

第三部分第三章 自己动手开发Button控件

NCS自定义控件的开发

NCS具有很强的扩展性,用户可以根据自身需求,随心所欲的开发NCS自定义控件。
下面我们将讲解如何在NCS中自定义控件。

NCS的继承机制

在NCS中自定义控件,就不得不介绍NCS的继承机制,因为它可以方便开发者利用现有类进行高效率的开发。
NCS的框架是基于OO思想的, 利用C语言的函数指针模拟C++中的虚拟函数实现多态。
在继承上, 实现C用宏来模拟继承, 即保持子类结构的前半部分与父类结构在语义方面和语法方面都保持一致 。
一个控件由三部分组成:
  • 1. 控件的属性集合
  • 2. 控件的虚函数表
  • 3. 控件渲染器的接口

例如 mWidget:
mWidget是所有控件的基础类 ,继承自: mComponent 。
类Wideget介绍

自定义控件的功能需求

button_n.png button_n_d.png
自定义一个NCS button控件,控件的外观使用两张图片实现(如上图),这两张图片分别代表按钮的按下和抬起。
当button在按下或抬起的时候分别更换不同的图片,表示控件自身处于的不同状态,同时会向父窗口发送通知事件。

选择哪个类作为自定义控件的基类

作为新控件的开发,需要选择一个适合自身需求的基类,我们这里选择Widget作为基类。

开始自定义控件的编码工作

自定义控件的命名

对于自定义控件的命名,NCS中有详细的规范。参见:新控件集的接口命名规范
在这里我们将新控件命名为"newbutton"。
#define NCSCTRL_NEWBUTTON    NCSCLASSNAME("newbutton")

自定义控件的定义

在这里定义,自定义控件中需要使用的变量和虚函数。从下面的定义中可以看到,Header、ClassHeader、RendererHeader都继承自Widget类。
/*在这里定义了,两张图片的PBITMAP,和button所处的状态标实*/
#define mNewButtonHeader(clsName) \
mWidgetHeader(clsName)        \
PBITMAP bmp_nor;              \
PBITMAP bmp_up;               \
int status;

#define mNewButtonClassHeader(clsName, parentClass)           \
mWidgetClassHeader(clsName, parentClass)    

#define mNewButtonRendererHeader(clsName, parentClass)  \
mWidgetRendererHeader(clsName, parentClass)

MGNCS_EXPORT extern mNewButtonClass g_stmNewButtonCls;

自定义控件的Property和Notify

定义自定义控件的属性、通知消息。因为该类的父类是Widget所以,要从*_WIDGET_MAX + 1开始定义。
enum mNewbuttonProp {
        NCSP_NEWBTN_IMAGE_NORMAL = NCSP_WIDGET_MAX + 1,
        NCSP_NEWBTN_IMAGE_DOWN,
        NCSP_NEWBTN_MAX
};

enum mNewButtonNotify {
        NCSN_NEWBTN_PUSHED = NCSP_WIDGET_MAX + 1
};

自定义控件中虚函数的实现

/*控件中定义的枚举类型,表示button的两个状态*/
enum mNewButtonStatus {
        BTN_NORMAL   = 1,
        BTN_PUSHED
};
在头文件中定义完了,变量和虚函数,就需要在C文件中实现这些虚函数,并使用这些变量了。
/*类mNewButton的构造函数*/
static void mNewButton_construct(mNewButton *self, DWORD param)
{
        Class(mWidget).construct((mWidget*)self, param);
}

/*类mNewButton的onLButtonDow和onLButtonUp函数,其作用是接收鼠标事件,并通知父窗口。*/
static int mNewButton_onLButtonDown (mNewButton* self, int x, int y, DWORD keyFlags)
{
        SetCapture (self->hwnd);
        self->status = BTN_PUSHED;
        InvalidateRect(self->hwnd, NULL, TRUE);
        return 0;
}

static int mNewButton_onLButtonUp (mNewButton* self, int x, int y, DWORD keyFlags)
{
        if (GetCapture() == self->hwnd){
                self->status = BTN_NORMAL;
                InvalidateRect(self->hwnd, NULL, TRUE);
                ReleaseCapture ();
                ncsNotifyParent((mWidget*)self, NCSN_NEWBTN_PUSHED);
        }
}

/*类mNewButton onPaint的处理函数,其作用是根据button的不同状态,显示不同的图片*/
static void mNewButton_onPaint (mNewButton *self, HDC hdc, const PCLIPRGN pinv_clip)
{
        RECT rect;
        GetWindowRect (self->hwnd, &rect);
        switch (self->status){
                case BTN_NORMAL:
                FillBoxWithBitmap (hdc, 0, 0, RECTW(rect), 
                RECTH(rect), self->bmp_nor);
                break;
                case BTN_PUSHED:
                FillBoxWithBitmap (hdc, 0, 0, RECTW(rect), 
                RECTH(rect), self->bmp_up);
                break;
        }
}

/*类mNewButton setProperty的处理函数,其作用是加载图片,并将其显示出来。*/
static BOOL mNewButton_setProperty (mNewButton *self, int id, DWORD value)
{
        char *str;
        if (id > NCSP_NEWBTN_MAX){
                return FALSE;
        }
        str = (char*)value;
        switch (id){
                case NCSP_NEWBTN_IMAGE_NORMAL:
                self->bmp_nor = LoadBitmapFromRes (HDC_SCREEN, str);
                if (self->bmp_nor == NULL){
                        printf ("Cant load %s\n ", str);
                        return 1;
                }
                break;
                
                case NCSP_NEWBTN_IMAGE_DOWN:
                self->bmp_up = LoadBitmapFromRes (HDC_SCREEN, str);
                if (self->bmp_up == NULL){
                        printf ("Cant load %s\n ", str);
                        return 1;
                }
                break;
        }
        InvalidateRect(self->hwnd, NULL, TRUE);
        return Class(mWidget).setProperty((mWidget*)self, id, value);
}

/*类mNewButton 在销毁的时候使用的destroy函数,其作用是释放使用的图片资源*/
static void mNewButton_destroy(mNewButton *self)
{
        ReleaseRes (Str2Key (self->bmp_nor));
        ReleaseRes (Str2Key (self->bmp_up));
}
/*类mNewButton onCreate的处理函数,其作用是将button的status置为BTN_NORMAL*/
static BOOL mNewButton_onCreate (mNewButton *self, LPARAM lParam)
{
        self->status = BTN_NORMAL;
}

自定义控件效果

下面就是自定义控件在窗口上的显示效果。
图中定义了三个newbutton控件。
custom_button.png

上一章<目录 >


Topic attachments
I Attachment Action Size Date Who Comment
pngpng button_n.png manage 8.4 K 09 Mar 2010 - 13:57 RongBiao  
pngpng button_n_d.png manage 7.9 K 09 Mar 2010 - 13:57 RongBiao  
pngpng custom_button.png manage 13.2 K 09 Mar 2010 - 13:57 RongBiao  
Edit | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r2 < r1 | More topic actions
 
Powered by TWiki
This site is powered by the TWiki collaboration platformCopyright © by the Feynman Software and/or the contributing authors. All material on this collaboration platform is the property of Feynman Software and/or the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback