windows 实现一个简单的自绘边框,具有最大化,最小化,icon,标题

实现一个简单的自绘边框,具有最大化,最小化,icon,标题.

当用户嫌windows的框架颜色不好看,要修改窗口的框架,就自己在win32上实现它,因为内容是使用cef框架实现,使用duilib 等界面库和cef的demo代码兼容性有些问题.

实现效果:
windows 实现一个简单的自绘边框,具有最大化,最小化,icon,标题_第1张图片

设计

  • 1 popup 窗口,overlapped 窗口有标题,菜单,一些限制
  • 2 定义客户区和非客户区
    目的是在不同的区域返回不同的标志 。主要在 WM_NCHITTEST 中处理
    分为:
    1 标题区,去掉 最大,最小,关闭 三个按钮的上面 20-30 px 的区域,可以拖动窗口
    2 左上右上左下右下,上,下 左 右 ,这些区域都支持拉伸
    3 客户区,除去这些地方
  • 3 处理 WM_LBUTTONDOW WM_LBUTTONUP WM_MOUSEMOVE WM_MOUSELEAVE
  • 4 处理 WM_NCLBUTTONDBCLK 双击最大化,最小化
  • 5 绘制窗口 处理 WM_PAINT
  • 6 处理 WM_SIZE
  • 7 实现按钮类
  • 8 实现一个icon 类
  • 9 实现窗口的setting类
  • 10 实现窗口管理类

设计完成之后,实现

1 注册窗口
2 创建窗口
3 窗口过程函数得到窗口类指针,调用类中的函数 OnPaint,OnSize,OnLButtonDown,OnLButtonUp,OnMouseMove,OnNCHitTest
4 定义区域
5 绘制区域

窗口过程函数代码如下:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_CREATE:
		__asm  nop;
		CenterWindow(hWnd);
		OnCreate(hWnd);
		break;
	case WM_SIZE:
		OnSize(hWnd,wParam,lParam);
		break;
	case WM_MOUSELEAVE:
		OnMouseLeave(hWnd,wParam,lParam);
		break;
	case WM_MOUSEMOVE:
		OnMouseMove(hWnd,wParam,lParam);
		break;
	
	case WM_NCLBUTTONDBLCLK:
			g_sys_frame.OnNcLButtionDbClk(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONUP:
		OnLButtonUp(hWnd,wParam,lParam);
		break;
	case WM_LBUTTONDOWN:
		OnLButtonDown(hWnd,wParam,lParam);
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 分析菜单选择:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_WINDOWPOSCHANGED:
		{
			WINDOWPOS * p = (WINDOWPOS*)lParam;
			int nMinWidth = 500;
			if(p->cxcy,SWP_NOMOVE);
			}
			break;
		}
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		OnPaint(hWnd,hdc);
		EndPaint(hWnd, &ps);
		break;
	case WM_NCHITTEST:
		return g_sys_frame.OnNcHitTest(hWnd,wParam,lParam);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

封装了一些On函数,这些函数在再调用类实现

void OnPaint(HWND hWnd,HDC hdc)
{
	g_sys_frame.OnPaint(hWnd,hdc);	
}
void OnCreate(HWND wnd)
{
	g_sys_frame.Create(wnd);
}


void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	g_sys_frame.OnLButtonDown(hWnd,wParam,lParam);
}
void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	g_sys_frame.OnLButtonUp(hWnd,wParam,lParam);
}
void OnMouseLeave(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	g_sys_frame.OnMouseLeave(hWnd);
}
void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	g_sys_frame.OnMouseMove(hWnd,wParam,lParam);
}
void OnSize(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	RECT rcWin;
	GetClientRect(hWnd,&rcWin);
	g_sys_frame.OnSize(hWnd,wParam,lParam);
	InvalidateRect(hWnd,&rcWin,FALSE);
}

g_sys_frame 是一个窗口的实现类

#ifndef system_frame_h
#define system_frame_h
#include "MyCloseBtn.h"
#include "MyMinBtn.h"
#include "MyMaxBtn.h"
#include "MyIcon.h"

//窗口的系统组件
//1 如何处理拉伸
//2 系统的按钮,最大,最小,关闭,icon,标题

//拉伸的矩形
struct ResizeRect
{
	//拉伸的标志,HTLEFT ...
	LRESULT resize_flag;
	//拉伸的矩形
	RECT resize_rect;
	ResizeRect(){}
	ResizeRect(RECT &rc,LRESULT flag)
	{
		resize_rect = rc;
		resize_flag = flag;
	}
	void SetResizeRect(RECT &rc,LRESULT flag)
	{
		resize_rect = rc;
		resize_flag = flag;
	}
};


RECT MoveRectEx(RECT &rc,int dx,int dy)
{
	RECT rcTmp=rc;
	OffsetRect(&rcTmp,dx,dy);
	return rcTmp;
}
inline RECT GenRect(int x,int y,int width,int height)
{
	RECT rc={x,y,x+width,y+height};
	return rc;
}
inline void GenResizeRect(RECT &rcWin,vector & ret_vec)
{
	const int border_width = sys_frame_settings::get().border_width*4;
	const int x_off = RECT_WIDTH(rcWin)-border_width*2;
	const int y_off = RECT_HEIGHT(rcWin)-border_width*2;
	//左上
	RECT rc={0,0,border_width,border_width};
	ret_vec.push_back(ResizeRect(rc,HTTOPLEFT));
	ret_vec.push_back(ResizeRect(MoveRectEx(rc,x_off,0),HTTOPRIGHT));
	ret_vec.push_back(ResizeRect(MoveRectEx(rc,0,y_off),HTBOTTOMLEFT));
	ret_vec.push_back(ResizeRect(MoveRectEx(rc,x_off,y_off),HTBOTTOMRIGHT));

	//上
	rc = GenRect(border_width,0,x_off,border_width);
	ret_vec.push_back(ResizeRect(rc,HTTOP));
	ret_vec.push_back(ResizeRect(MoveRectEx(rc,0,y_off),HTBOTTOM));
	
	//左
	rc = GenRect(0,border_width,border_width,y_off);
	ret_vec.push_back(ResizeRect(rc,HTLEFT));
	ret_vec.push_back(ResizeRect(MoveRectEx(rc,x_off,0),HTRIGHT));
}


//系统按钮和icon 标题实现
struct SysButtons
{
	CMyBtn *g_close_btn;
	CMyBtn *g_min_btn;
	CMyBtn *g_max_btn;
	CMyIcon* g_icon;
	int m_mouse_state;
	BOOL m_bEnable;
	void SetEnable(BOOL b)
	{
		m_bEnable = b;
	}
	BOOL isEnable()
	{
		return m_bEnable;
	}
	SysButtons()
	{
		m_bEnable = FALSE;
		g_max_btn=NULL;
		g_min_btn=NULL;
		g_close_btn=NULL;
		g_icon=NULL;
		m_mouse_state = 0;
	}
	void Create(HWND wnd)
	{
		g_close_btn = new CMyCloseBtn();
		g_close_btn->m_parent = wnd;
		RECT rcWin;
		GetClientRect(wnd,&rcWin);
		g_close_btn->CorrectRect(rcWin);

		g_min_btn = new CMyMinBtn();
		g_min_btn->m_parent = wnd;
		g_min_btn->CorrectRect(rcWin);

		g_max_btn = new CMyMaxBtn();
		g_max_btn->m_parent = wnd;
		g_max_btn->CorrectRect(rcWin);

		g_icon = new CMyIcon();

		g_icon->CorrectRect(rcWin);
	}
	void OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		g_close_btn->OnLButtonUp(hWnd,wParam,lParam);
		g_min_btn->OnLButtonUp(hWnd,wParam,lParam);
		g_max_btn->OnLButtonUp(hWnd,wParam,lParam);
	}
	void OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		g_close_btn->OnLButtonDown(hWnd,wParam,lParam);
		g_min_btn->OnLButtonDown(hWnd,wParam,lParam);
		g_max_btn->OnLButtonDown(hWnd,wParam,lParam);
	}
	void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		if(m_mouse_state==0)
		{
			TRACKMOUSEEVENT te={sizeof(TRACKMOUSEEVENT ),TME_LEAVE,hWnd};
			TrackMouseEvent(&te);

			m_mouse_state = 1;
		}
		g_close_btn->OnMouseMove(hWnd,wParam,lParam);
		g_min_btn->OnMouseMove(hWnd,wParam,lParam);
		g_max_btn->OnMouseMove(hWnd,wParam,lParam);
	}
	void OnSize(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		CorrectBtns(hWnd);
	}
	void OnMouseLeave(HWND hWnd)
	{
		m_mouse_state = 0;
		g_close_btn->OnMouseLeave(hWnd);
		g_min_btn->OnMouseLeave(hWnd);
		g_max_btn->OnMouseLeave(hWnd);
	}
	LRESULT OnNcHitTest(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{

		int x;
		int y;
		x = LOWORD(lParam);
		y = HIWORD(lParam);
		RECT rcWin;
		GetClientRect(hWnd,&rcWin);
		RECT rcTitle;
		sys_frame_settings::get().GetTitleRect(rcWin,rcTitle);
		POINT pt={x,y};
		ScreenToClient(hWnd,&pt);
		CheckAndRedraw(hWnd,pt);

		if(PtInCaption(hWnd,wParam,lParam))
		{
			return HTCAPTION;
		}
		vector vec;
		GenResizeRect(rcWin,vec);
		for(size_t i=0;iPtInRect(pt))
		{
			g_min_btn->SetState(BTN_STATE_NORMAL);
			if(g_min_btn->isChanged())
			{
				InvalidateRect(hWnd,&g_min_btn->m_rt,TRUE);
			}
		}
		if(!g_max_btn->PtInRect(pt))
		{
			g_max_btn->SetState(BTN_STATE_NORMAL);
			if(g_max_btn->isChanged())
			{
				InvalidateRect(hWnd,&g_max_btn->m_rt,TRUE);
			}
		}
		if(!g_close_btn->PtInRect(pt))
		{
			g_close_btn->SetState(BTN_STATE_NORMAL);
			if(g_close_btn->isChanged())
			{
				InvalidateRect(hWnd,&g_close_btn->m_rt,TRUE);
			}
		}
	}
	HRGN GenFromRect(RECT &rc)
	{
		return CreateRectRgn(rc.left,rc.top,rc.right,rc.bottom);
	}
	void CorrectBtns(HWND hWnd)
	{
		RECT rcWin;
		GetClientRect(hWnd,&rcWin);
		g_max_btn->CorrectRect(rcWin);
		g_min_btn->CorrectRect(rcWin);
		g_close_btn->CorrectRect(rcWin);
		g_icon->CorrectRect(rcWin);
	}
	HRGN GetRgn(HWND hWnd)
	{
		CorrectBtns(hWnd);

		HRGN rgnMax = GenFromRect(g_max_btn->m_rt);
		HRGN rgnMin = GenFromRect(g_min_btn->m_rt);
		HRGN rgnClose = GenFromRect(g_close_btn->m_rt);
		CombineRgn(rgnMax,rgnMax,rgnMin,RGN_OR);
		CombineRgn(rgnMax,rgnMax,rgnClose,RGN_OR);
		DeleteObject(rgnMin);
		DeleteObject(rgnClose);
		return rgnMax;
	}
	void OnPaint(HWND hWnd,HDC hdc)
	{
		//绘制边框
		RECT rcWin;
		GetClientRect(hWnd,&rcWin);
		HBRUSH br = CreateSolidBrush(sys_frame_settings::get().border_corlor);
		for(int i=0; iDraw(hdc);
		g_min_btn->Draw(hdc);
		g_max_btn->Draw(hdc);
		g_icon->Draw(hdc);
	}
	void SetMaximizeState(HWND hWnd)
	{
		g_max_btn->SetMaximizeState(hWnd);
	}
	BOOL PtInCaption(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		int x;
		int y;
		x = LOWORD(lParam);
		y = HIWORD(lParam);
		RECT rcWin;
		GetClientRect(hWnd,&rcWin);
		RECT rcTitle;
		sys_frame_settings::get().GetTitleRect(rcWin,rcTitle);
		POINT pt={x,y};
		ScreenToClient(hWnd,&pt);
		{
			RECT rt = g_close_btn->m_rt;
			WCHAR msg[256]={};
			wsprintf(msg,L"%d,%d,(%d,%d)-(%d,%d)",pt.x,pt.y,rt.left,rt.top,rt.right,rt.bottom);
			OutputDebugString(msg);
		}

		HRGN rgn = CreateRectRgn(rcTitle.left,rcTitle.top,rcTitle.right,rcTitle.bottom);
		HRGN rgnSysBtns = GetRgn(hWnd);

		int ret=CombineRgn(rgn,rgn,rgnSysBtns,RGN_DIFF);
		if(ret!=NULLREGION && ret!=ERROR)
		{
			if(PtInRegion(rgn,pt.x,pt.y))
			{
				DeleteObject(rgn);
				DeleteObject(rgnSysBtns);
				return TRUE;
			}
		}

		DeleteObject(rgn);
		DeleteObject(rgnSysBtns);
		return FALSE;
	}
	void OnNcLButtionDbClk(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		if(wParam == HTCAPTION)
		{
			SetMaximizeState(hWnd);
		}

	}
};

#endif

在这里调用类 CMyBtn 一些派生类 CMyMinBtn CMyIcon CMyMaxBtn CMyCloseBtn 实现按钮绘制和icon绘制

代码如下

#pragma once
/*
状态 : normal over down
显示 : 背景色,点阵数组,点阵颜色

*/
enum
{
	BTN_STATE_NORMAL,
	BTN_STATE_OVER,
	BTN_STATE_DOWN
};
enum {
	MAX_STATE_NORMAL,
	MAX_STATE_MAXIZED,	
};
enum {
	MOUSE_STATE_OFF,
	MOUSE_STATE_ON,
};
#include "win_settings.h"
inline int RECT_WIDTH(RECT &rc){return rc.right-rc.left;}

inline int RECT_HEIGHT(RECT &rc){return rc.bottom-rc.top;}

class CMyBtn
{
public:
	CMyBtn(void);
	~CMyBtn(void);
//
	int m_state;
	int m_old_state;
	RECT m_rt;
	HWND m_parent;
	BOOL m_bDown;
	void SetParent(HWND wnd)
	{
		m_parent = wnd;
	}
	void SetState(int state)
	{
		m_old_state = m_state;
		m_state = state;
	}
	bool isChanged()
	{
		return m_state != m_old_state;
	}
	int GetState()
	{
		return m_state;
	}
	void SetDownFlag(BOOL b)
	{
		m_bDown = b;
	}
	bool PtInRect(POINT pt)
	{
		return ::PtInRect(&m_rt,pt)?true:false;
	}
	int GetMaximizeState()
	{
		return m_max_state;
	}
	void SetMaximizeState(HWND hWnd)
	{
		if(m_max_state==MAX_STATE_NORMAL)
		{
			PostMessage(hWnd,WM_SYSCOMMAND,SC_MAXIMIZE,0);			
			m_max_state = MAX_STATE_MAXIZED;
		}
		else
		{
			PostMessage(hWnd,WM_SYSCOMMAND,SC_RESTORE,0);
			m_max_state = MAX_STATE_NORMAL;
		}

	}
	void SetMinize(HWND hWnd)
	{
		PostMessage(hWnd,WM_SYSCOMMAND,SC_MINIMIZE,0);
	}
	virtual BOOL OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		int x;
		int y;
		x =  LOWORD(lParam); 
		y = HIWORD(lParam);
		POINT pt={x,y};
		if(PtInRect(pt))
		{
			SetState(BTN_STATE_NORMAL);
			InvalidateRect(hWnd,&m_rt,TRUE);
			SetDownFlag(FALSE);
			return TRUE;
		}
		return FALSE;
	}
	virtual void OnMouseLeave(HWND hWnd)
	{
		SetState(BTN_STATE_NORMAL);
		InvalidateRect(hWnd,&m_rt,TRUE);
	}
	virtual void OnMouseMove(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		int x;
		int y;
		x =  LOWORD(lParam); 
		y = HIWORD(lParam);
		POINT pt={x,y};
		if(PtInRect(pt))
		{
			SetState(BTN_STATE_OVER);
			InvalidateRect(hWnd,&m_rt,TRUE);
		}
		else
		{
			SetState(BTN_STATE_NORMAL);
			if(isChanged())
			{
				InvalidateRect(hWnd,&m_rt,TRUE);
			}
		}
	}
	virtual BOOL OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)
	{
		int x;
		int y;
		x =  LOWORD(lParam); 
		y = HIWORD(lParam);
		POINT pt={x,y};
		if(PtInRect(pt))
		{
			SetState(BTN_STATE_DOWN);
			InvalidateRect(hWnd,&m_rt,TRUE);
			SetDownFlag(TRUE);
			return TRUE;
		}
		return FALSE;
	}
	virtual void CorrectRect(RECT &rcWin)
	{
		
	}
	int m_max_state;

	virtual void Draw(HDC hdc);
};

派生类

#pragma once
#include "mybtn.h"
class CMyMaxBtn :
	public CMyBtn
{
public:
	CMyMaxBtn(void);
	~CMyMaxBtn(void);
	virtual void Draw(HDC hdc);
	virtual BOOL OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam);
	virtual void CorrectRect(RECT &rcWin);
	BYTE m_maxize_pic[100];
	BYTE m_normal_pic[100];
};

#pragma once
#include "mybtn.h"

class CMyMinBtn :
	public CMyBtn
{
public:
	CMyMinBtn(void);
	~CMyMinBtn(void);
	virtual void Draw(HDC hdc);
	virtual BOOL OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam);
	virtual void CorrectRect(RECT &rcWin);
};

#pragma once
#include "mybtn.h"

class CMyCloseBtn :
	public CMyBtn
{
public:
	CMyCloseBtn(void);
	~CMyCloseBtn(void);
	virtual void Draw(HDC hdc);
	virtual BOOL OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam);
	virtual void CorrectRect(RECT &rcWin);
	unsigned char m_normal_pic[100];
};

还有一个总的setting 类,里面定义,窗口的背景色,边框颜色,边框宽度,字体等等

#ifndef _settings_h_
#define _settings_h_
//窗体的配置参数
//注意:边框过窄会导致窗口改变大小不方便
class sys_frame_settings
{
public:
	sys_frame_settings()
	{
		border_corlor = RGB(128,128,128);
		title_bk_color = RGB(2,167,240);
		title_text_color= RGB(255,255,255);
		title_height = 23;
		border_width = 1;

	}
	static sys_frame_settings & get(){
		static sys_frame_settings a;
		return a;
	}
	void setWinRect(RECT &rt)
	{
		rcWin = rt;
	}
	void SetTitleRect(RECT &rt)
	{
		rcTitle = rt;
	}
	void GetTitleRect(RECT &rcWin,RECT &rcTitle)
	{
		rcTitle = rcWin;
		InflateRect(&rcTitle,-1*border_width,-1*border_width);
		rcTitle.bottom = rcTitle.top+title_height;
	}
	void GetCaptionRect(RECT &rcWin,RECT &ret_rt)
	{
		ret_rt = rcWin;
		InflateRect(&ret_rt,-1*border_width,-1*border_width);
		ret_rt.left = ret_rt.left+10+16;
		ret_rt.bottom=ret_rt.top+title_height;
	}
	//边框色
	COLORREF border_corlor;
	//标题背景色
	COLORREF title_bk_color;
	//
	COLORREF title_text_color;
	//标题高度
	int title_height;
	//标题位置和大小
	RECT rcTitle;
	//窗口位置和大小
	RECT rcWin;
	//关闭按钮
	RECT rcClose;
	//最大化按钮
	RECT rcMax;
	//最小化按钮
	RECT rcMin;
	//边框宽度
	int border_width;
};


#endif

此程序关键是如下的知识:

  • 窗体的知识: 客户区非客户区
  • 鼠标消息处理
  • 区域
  • 绘画
  • 窗口的一些基础知识,窗口类,注册,创建。
  • c++一些知识

你可能感兴趣的:(学习,系统编程,经验,windows,vs,窗口框架,自绘,c++)