VC中利用WinAPI实现自绘按钮类

VC中利用WinAPI实现自绘按钮类,第1张

VC中利用WinAPI实现自绘按钮类,第2张

俗话说,佛要金衣,人要衣装。当然,软件开发者需要一个好的界面。网上提供的控件自绘基本都是MFC或者WTL封装的类,对于不想用MFC的人来说没什么用。我是WIN32API的坚定支持者。因为MFC之类的也是用WIN32API封装的,学好WIN32API就能对Windows的内部机制有深入的了解,写出来的程序也能更好的优化。

我们来分析一下自绘按钮的原理。用过MFC自绘按钮的人都知道,它是通过重载父窗口WM_DRAWITEM的响应消息实现的。同时要对按钮进行子类化,以获取按钮的其他有用消息,如WM_MOUSEMOVE、WM_KEYDOWN等。因为MFC的消息循环都是封装的,所以只需要派生基本的控件类。用WIN32API完成后,需要自己子类化按钮窗口的消息循环。相信经常编程的朋友都知道,子类化控件需要使用SetWindowLong来改变窗口的回调过程,然后在回调窗口中添加你需要处理的消息。因为我们要实现自绘按钮,所以要把子类化的过程做成一个类,然后把要自绘的按钮的句柄传给它。因为消息回调函数应该在类中实现,但是类中的消息回调函数只能是静态的,所以不能对应每个实例的消息回调。在我实现的button子类类中,我使用了Thunk技术或者SetProp函数来实现。详情请上网查。

我来说说自绘按钮最重要的部分,就是在按钮消息函数中响应WM_PAINT消息。我们所有的自画动作都在这里进行。WM_PAINT中的绘制操作和普通窗口是一样的,但是为了跟踪按钮的当前状态,我们要在按钮窗口中响应WM_MOUSEMOVE、WM_SETFOCUS、WM_KILLFOCUS、WM_LBUTTONDOWN、WM_ENABLE等消息来获取当前的按钮状态。于是,在WM_PAINT中可以画出不同的状态,可以实现的东西很多。基本上想实现多少就能实现多少,看个人喜好了。你可以修改我提供的源代码。我也看了ButtonST里的自画代码。我添加了右键拖动功能和鼠标悬停功能。有兴趣可以自己添加,锻炼编程能力。

我来说说我做的这堂课的一道题。我把button类做成一个动态库。调用时,我只需要添加我的头文件和连接的lib库。我的动态库在WIN32加载没有问题,但是在MFC中,需要响应父窗口的WM_DRAWITEM消息,直接返回,而不是调用MFC的默认处理。这是因为我没有截获父窗口的WM_DRAWITEM消息,否则关闭程序时会有非法操作!主要代码分析如下:


自画按钮类声明:

classl port cwin button
{
public:
//初始化按钮(这是第一步!)
BOOL GetItemhWnd(HWND HWND);
//还原按钮区域设置
BOOL Restore();
//设置按钮是否可以拖动
BOOL Set drag(BOOL Enable);
//设置按钮图标
BOOL SetIcon(HICON图标);
//设置按钮文本
Bool SetText (char * text,hfont font);
BOOL SetText(char * text);
BOOL SetText(char *text,COLORREF color);
//设置按钮有效区域
Bool设置区域(colorref trans color);
LRESULT OnPaint(HDC HDC);
//设置按钮无效时的图片
bool setdisablepic(hbit map BMP);
//设置按钮按下时的图片
Bool Setpresspic(hbit map BMP);
//设置悬停按钮时的图片
Bool SetHoverpic(hbit map BMP);
//设置按钮背景图片,第二个参数是是否根据图片调整按钮大小
Bool缩进Pic (HBITMAP BMP,Bool B Resize);
//设置按钮的提示信息
BOOL SetToolTip(char * text);
cwin button();
virtual ~ cwin button();

private:
static LRESULT WINAPI stdProc(HWND HWND,UINT uMsg,UINT wParam,LONG lParam);
WNDPROC GetThunk();
WNDPROC create thunk();
LRESULT回调WINProc(UINT message,WPARAM wParam,LPARAM LPARAM);
BOOL DrawInsideBorder(HDC DC,RECT * rect);
BOOL DrawFlat(HDC dc,RECT * rect);
BOOL draw default(HDC DC);
HWND m _ ToolTip;
HWND m _ HWND;
HWND m _ HWND parent;
LONG m _ old proc;
WNDPROC m _ thunk;
tool info ti;
HICON m _ icon;
hbit map m _ Back;//按钮背景图片
hbit map m _ Hove;//鼠标悬停时的按钮背景图片
hbit map m _ Press;//鼠标按下时的按钮背景图片
hbit map m _ Disable;//按钮无效时的背景图像
BITMAP BM;
COLORREF m _ text color;//按钮文本的颜色
BOOL m _ bMouseTracking;//确定鼠标是否在窗口中
BOOL m _ b press;//确定鼠标是否按下了
BOOL m _ Enable;//控件是否有效
BOOL m _ b focus;//按钮是否处于输入焦点
BOOL m _ bowner draw;//确定用户是否自己映射
BOOL m _ bDrag;//是否处于拖动状态
BOOL m _ bDragEnable;//是否允许拖动
char m _ text[MAX _ text len];//按钮文本
char m _ tip text[max _ text len];//按钮提示文本
HFONT m _ font;//按钮文本字体
h cursor m _ old cursor;
RECT m _ ParentRt;
RECT m _ begin rt;
RECT m _ current rt;
点m _ BeginPt
点m _ CurrentPt
int m _ caption height;
int m _ border width;
int m _ edge width;

protected:
/按钮的外边框
HPEN m _ BoundryPen;

//当鼠标指针位于按钮上时按钮的内边框
hpen m _ InsideBoundypenleft;
HPEN m _ insideboundypenright;
HPEN m _ insideboundypentop;
HPEN m _ insideboundypebottom;

//按钮获得焦点时的内边框
hpen m _ InsideBoundypenleftsel;
HPEN m _ insideboundypenrightsel;
HPEN m _ insideboundypentopsel;
HPEN m _ insideboundypebottomsel;

//按钮的背景色,包括有效和无效状态
HBRUSH m _ fill active;
HBRUSH m _ fill inactive;
};

回调类中的实现代码:

In CWINButton::GetItemhWnd()

if(SetProp(m_hWnd," CWINBUTTON ",(HANDLE)this)= = 0)
{
OutputDebugString(" set prop ERROR ");
返回FALSE
}

m_OldProc = SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)STD proc);

in cwin button::STD proc()
{
cwin button * w =(cwin button *)get prop(hwnd," cwin button ");
return w->WINProc(uMsg,wParam,lParam);
}

Thunk代码可以在我的代码里或者网上找到。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » VC中利用WinAPI实现自绘按钮类

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情