【MFC自绘窗口】窗口设计第二课

开始重绘标题栏,首先先添加消息映射,在属性面板中找到WM_NCPAINT,好,添加

在刚生成的OnNcPaint函数中,我们就可以处理非客户区了

首先,我们先说一下CDC,CPaintDC,CClientDC,CWindowDC区别,

先看一下他们之间的关系

CObject

public |——CDC

public |——|——CClientDC

public |——|——CPaintDC

public |——|——CWindowDC

public |——|——CMetaFileDC

CDC是他们几个的基类

CDC是Windows绘图设备的基类

CClientDC:

1.(客户区设备上下文)用于客户区的输出,与特定窗口关联,可以让开发者访问目标窗口中客户区,其构造函数中包含了GetDC,析构函数中包含了ReleaseDC

CPaintDC:

1.用于响应窗口重绘消息(WM_PAINT)是的绘图输出。

2.CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。

3.CPaintDC也只能用在WM_PAINT消息处理之中。

CWindowDC:

1.可在非客户区绘制图形,而CClientDC,CPaintDC只能在客户区绘制图形。

2.坐标原点是在屏幕的左上角,而CClientDC,CPaintDC的坐标原点是在客户区的左上角。

3.关联一特定窗口,允许开发者在目标窗口的任何一部分进行绘图,包含边界与标题,这种DC同WM_NCPAINT消息一起发送

说明:在绘图时推荐使用CClientDC,CPaintDC和CWindowDC对象,而不推荐直接使用CDC对象。

言归正传, 添加绘制标题栏函数DrawTitleBar,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma once
     
     
// CDialogEx 对话框
#include "ImageEx.h"
     
class  CDialogEx :  public  CDialog
{
     DECLARE_DYNAMIC(CDialogEx)
         
     //加载资源
protected :
     CImageEx                    m_ImageTitleL;
     CImageEx                    m_ImageTitleM;
     CImageEx                    m_ImageTitleM_Spe;
     CImageEx                    m_ImageTitleR;
     
public :
     CDialogEx( UINT  nIDTemplate,CWnd* pParent = NULL);    // 标准构造函数
     virtual  ~CDialogEx();
     
     //消息映射
public :
     //修改尺寸
     afx_msg  void  OnNcCalcSize( BOOL  bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp);
     //非客户区绘制
     afx_msg  void  OnNcPaint();
     
protected :
     //
     virtual  void  DoDataExchange(CDataExchange* pDX);     // DDX/DDV 支持
     virtual  BOOL  OnInitDialog();
     
     DECLARE_MESSAGE_MAP()
     
     //绘制函数
public :
     //绘制标题
     void  DrawTitleBar(CDC*pDC);
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// DialogEx.cpp : 实现文件
//
     
#include "stdafx.h"
#include "Design.h"
#include "DialogEx.h"
     
CONST  INT    nTitleHeight=33;
CONST  INT    nFrameBorerL=2;
CONST  INT    nFrameBorerR=2;
CONST  INT    nFrameBorerB=2;
// CDialogEx 对话框
     
IMPLEMENT_DYNAMIC(CDialogEx, CDialog)
     
CDialogEx::CDialogEx( UINT  nIDTemplate, CWnd * pParentWnd)
     : CDialog(nIDTemplate,pParentWnd)
{
     
}
     
CDialogEx::~CDialogEx()
{
}
     
void  CDialogEx::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
}
     
     
BEGIN_MESSAGE_MAP(CDialogEx, CDialog)
     ON_WM_NCPAINT()
     ON_WM_NCCALCSIZE()
END_MESSAGE_MAP()
     
     
// CDialogEx 消息处理程序
     
void  CDialogEx::OnNcPaint()
{
     CWindowDC dc( this );
     
     DrawTitleBar(&dc);
}
     
void  CDialogEx::DrawTitleBar( CDC*pDC )
{
     if  ( GetSafeHwnd() == NULL )  return ;
         
     CRect rtWnd, rtTitle, rtButtons;
     GetWindowRect(&rtWnd);
         
     //标题栏位置
     rtTitle.SetRect(0,0,rtWnd.right,nTitleHeight);
     
     if  ( !m_ImageTitleL.IsNull() )
     {
         //绘画背景
         m_ImageTitleL.BitBlt(pDC->GetSafeHdc(),0,0);
     
         //填充中间
         for  ( INT nXPos=m_ImageTitleL.GetWidth();nXPos<rtWnd.Width();nXPos+=m_ImageTitleM.GetWidth())
         {
             m_ImageTitleM.BitBlt(pDC->GetSafeHdc(),nXPos,0);
         }
         //填充中间特殊背景图片
         m_ImageTitleM_Spe.BitBlt(pDC->GetSafeHdc(),(rtWnd.Width()-m_ImageTitleM_Spe.GetWidth())/2,0);
     
         //绘画背景
         m_ImageTitleR.BitBlt(pDC->GetSafeHdc(),rtWnd.Width()-m_ImageTitleR.GetWidth(),0);
     }
     
     
     //绘制左边框
     CPoint point;
     point.x = nFrameBorerL;
     point.y = rtWnd.Height();
     pDC->FillSolidRect(0, nTitleHeight, point.x, point.y, RGB(10,10,10));
         
     //绘制下边框
     point.x = rtWnd.Width();
     point.y = nFrameBorerB;
     pDC->FillSolidRect(0, rtWnd.Height()-point.y, point.x, point.y, RGB(10,10,10));
         
     //绘制右边框
     point.x = nFrameBorerR;
     point.y = rtWnd.Height();
     pDC->FillSolidRect(rtWnd.Width()-point.x, nTitleHeight, point.x, point.y, RGB(10,10,10));
}
     
BOOL  CDialogEx::OnInitDialog()
{
     CDialog::OnInitDialog();
     
     //变量定义
     HINSTANCE  hInstance=AfxGetInstanceHandle();
     
     m_ImageTitleL.LoadImage(hInstance,TEXT( "TITLE_L" ));
     m_ImageTitleM.LoadImage(hInstance,TEXT( "TITLE_M" ));
     m_ImageTitleM_Spe.LoadImage(hInstance,TEXT( "TITLE_M_SPE" ));
     m_ImageTitleR.LoadImage(hInstance,TEXT( "TITLE_R" ));
     
     return  TRUE;   // return TRUE unless you set the focus to a control
}
     
void  CDialogEx::OnNcCalcSize( BOOL  bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
     lpncsp->rgrc[0].top+=nTitleHeight-GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYSIZEFRAME);;
     lpncsp->rgrc[0].left+=nFrameBorerL-GetSystemMetrics(SM_CXFRAME);
     lpncsp->rgrc[0].right-=nFrameBorerR-GetSystemMetrics(SM_CXSIZEFRAME);
     lpncsp->rgrc[0].bottom-=nFrameBorerB-GetSystemMetrics(SM_CYSIZEFRAME);
     
     CDialog::OnNcCalcSize(bCalcValidRects, lpncsp);
}

上面我们 用到了一个消息WM_NCCALCSIZE,先看一下这个消息是干什么用的

函数原型:

afx_msg void OnNcCalcSize( BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp );

参数:

bCalcValidRects指定应用程序是否需要指定客户区的哪个部分包含了有效信息。Windows将把有效信息拷贝到新客户区的指定位置。如果这个参数为TRUE,则应用程序必须指定客户区的哪个部分有效。
lpncsp指向一个NCCALCSIZE_PARAMS数据结构,其中包含了应用程序可用于计算CWnd矩形(包括客户区、边框、标题和滚动条等)的新大小和位置的信息。

说明:
当客户区的大小和位置需要重新计算时,框架调用这个成员函数。通过处理这个消息,应用程序可以在窗口的大小和位置发生变化时控制窗口客户区的内容。
不论bCalcValidRects的值是什么,NCCALCSIZE_PARAMS结构的rgrc结构成员所指向的数组中的第一个矩形中包含了窗口的坐标。对于一个子窗口,这个坐标是相对于父窗口的客户区的。对于顶层窗口,该坐标是屏幕坐标。应用程序应当修改rgrc[0]矩形以反映客户区的大小和位置。
rgrc[1]和rgrc[2]矩形仅当bCalcValidRects为TRUE时有效。在这种情况下,rgrc[1]矩形中包含了被移动或改变大小的窗口的坐标。rgrc[2]矩形中包含了窗口被移动之前的客户区坐标。所有的坐标都是相对于父窗口或屏幕的。缺省的实现根据窗口特征计算客户区的大小(是否有滚动条,菜单等),并且将结果放入lpncsp。
注意 框架调用这个成员函数以允许你的应用程序处理一个Windows消息。传递给你的成员函数的参数反映了接收到消息时框架接收到的参数。如果你调用了这个函数的基类实现,则该实现将使用最初传递给消息的参数(而不是你提供给这个函数的参数)。

通过这个函数我们更改了标题栏高度和边框的宽度,好,那我们运行一下程序看看效果

基本的雏形完成了,但是当窗口失去焦点的时候 发现窗口绘制出现了问题, 又恢复到了原先的主题模样,解决办法,属性面板,点击重写按钮,找到DefWindowProc,添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LRESULT  CDialogEx::DefWindowProc( UINT  message,  WPARAM  wParam,  LPARAM  lParam)
{
     LRESULT  lrst=CDialog::DefWindowProc(message, wParam, lParam);
      
     if  (!::IsWindow(m_hWnd))
         return  lrst;
      
     if (message==WM_MOVE||message==WM_PAINT||message==WM_NCPAINT||message==WM_NCACTIVATE ||message == WM_NOTIFY)
     {
         OnNcPaint();
     }
      
     return  lrst;
     
     return  CDialog::DefWindowProc(message, wParam, lParam);
}

好,接下来绘制按钮,按钮是本文的重点

先随便找一个软件,看看标题栏上面的按钮都有什么变化,一般都有最小化,最大化,关闭三个按钮,其中窗口最大化的时候,最大化按钮就会变成窗口化按钮,其次,每个按钮都有三帧,正常状态,Hoven状态,按下状态。好,知道了内容要求,那么接下来分析一下设计思路,因为按钮位于非客户区,普通的CButton按钮无法放置在这里,为此只能用图片去模拟,既然是模拟这些按钮的各种状态,那么就要知道几个要点:

1:按钮所在的位置,RECT

2:鼠标位置,

3:鼠标经过,离开,按下,抬起状态

按照步骤一步一步来,先让按钮能显示出来,剩下的就好办了。

添加几个变量

1
2
3
4
5
6
7
8
9
10
11
12
     //按钮状态
private :
     BYTE                         m_cbNowHotIndex[3];                  //现在焦点
     BYTE                         m_cbNowButtonIndex;                  //按钮索引
     BYTE                         m_cbButtonState[3];                  //按钮状态
     CRect                       m_rcButton[3];                       //按钮位置
     //加载资源
protected :
     CImageEx                    m_ImageBt_Close;
     CImageEx                    m_ImageBt_Max;
     CImageEx                    m_ImageBt_Res;
     CImageEx                    m_ImageBt_Min;

在添加几个宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//按钮标识
#define BST_CLOSE                   0                                   //关闭按钮
#define BST_MAX_SIZE                1                                   //还原按钮
#define BST_MIN_SIZE                2                                   //缩小按钮
    
//按钮状态
#define BUT_EXIST                   0x01                                //按钮存在
#define BUT_NORMAL                  0x02                                //按钮正常
#define BUT_DISABLE                 0x04                                //按钮禁止
    
    
//无效数值
#define INVALID_BYTE                ((BYTE)(0xFF))                      //无效数值
//数组维数
#define CountArray(Array) (sizeof(Array)/sizeof(Array[0]))

接下来在OnInitDialog()初始化它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
m_ImageBt_Close.LoadImage(hInstance,TEXT( "BT_CLOSE" ));
m_ImageBt_Max.LoadImage(hInstance,TEXT( "BT_MAX" ));
m_ImageBt_Res.LoadImage(hInstance,TEXT( "BT_RESTORE" ));
m_ImageBt_Min.LoadImage(hInstance,TEXT( "BT_MIN" ));
    
//按钮状态
m_cbNowButtonIndex=INVALID_BYTE;
ZeroMemory(m_cbNowHotIndex, sizeof (m_cbNowHotIndex));
ZeroMemory(m_cbButtonState, sizeof (m_cbButtonState));
    
//设置按钮
m_cbButtonState[BST_CLOSE]=BUT_EXIST|BUT_NORMAL;
m_cbButtonState[BST_MAX_SIZE]=BUT_EXIST|BUT_NORMAL;
m_cbButtonState[BST_MIN_SIZE]=BUT_EXIST|BUT_NORMAL;

加载了资源, 剩下的就是贴图片,首先要知道位置, 这三个按钮很特殊,是根据窗口大小 变化随着移动的,所以我们必须要根据窗口的大小去计算这些坐标,添加WM_SIZE消息

1
2
3
4
5
6
7
8
9
10
11
12
13
void  CDialogEx::OnSize( UINT  nType,  int  cx,  int  cy)
{
     CDialog::OnSize(nType, cx, cy);
    
     //计算偏移
     INT  nYPos=1;
     INT  nXPos=cx-nCloseWidth;
    
     //设置位置
     m_rcButton[BST_CLOSE].SetRect(nXPos,nYPos,nXPos+nCloseWidth,nYPos+31);
     m_rcButton[BST_MAX_SIZE].SetRect(nXPos-nMaxWidth,nYPos,nXPos,nYPos+31);
     m_rcButton[BST_MIN_SIZE].SetRect(nXPos-nMaxWidth-nMaxWidth,nYPos,nXPos-nMaxWidth,nYPos+31);
}

鼠标位置有了,那么就是绘制了,添加DrawTitleButton函数,和绘制标题栏一样,同样在OnNcPaint函数内调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void  CDialogEx::DrawTitleButton( CDC*pDC )
{
     if ( !m_ImageBt_Close.IsNull() )
         m_ImageBt_Close.BitBlt(pDC->GetSafeHdc(),m_rcButton[BST_CLOSE].left,m_rcButton[BST_CLOSE].top,m_rcButton[BST_CLOSE].Width(),m_rcButton[BST_CLOSE].Height(),m_cbNowHotIndex[0]*m_rcButton[BST_CLOSE].Width(),0);
    
     if  (IsZoomed())
     {
         if ( !m_ImageBt_Res.IsNull() )  
             m_ImageBt_Res.BitBlt(pDC->GetSafeHdc(),m_rcButton[BST_MAX_SIZE].left,m_rcButton[BST_MAX_SIZE].top,m_rcButton[BST_MAX_SIZE].Width(),m_rcButton[BST_MAX_SIZE].Height(),m_cbNowHotIndex[1]*m_rcButton[BST_MAX_SIZE].Width(),0);
     }
     else
     {
         if ( !m_ImageBt_Max.IsNull() )  
             m_ImageBt_Max.BitBlt(pDC->GetSafeHdc(),m_rcButton[BST_MAX_SIZE].left,m_rcButton[BST_MAX_SIZE].top,m_rcButton[BST_MAX_SIZE].Width(),m_rcButton[BST_MAX_SIZE].Height(),m_cbNowHotIndex[1]*m_rcButton[BST_MAX_SIZE].Width(),0);
     }
        
     if ( !m_ImageBt_Min.IsNull() )  
         m_ImageBt_Min.BitBlt(pDC->GetSafeHdc(),m_rcButton[BST_MIN_SIZE].left,m_rcButton[BST_MIN_SIZE].top,m_rcButton[BST_MIN_SIZE].Width(),m_rcButton[BST_MIN_SIZE].Height(),m_cbNowHotIndex[2]*m_rcButton[BST_MIN_SIZE].Width(),0);
}

这里用到了一个API,IsZoomed,此函数判断窗口当前是否最大化。运行一下,是不是按钮显示出来了呢,下面为按钮增加状态


先添加WM_NCMOUSEMOVE消息,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void  CDialogEx::OnNcMouseMove( UINT  nHitTest, CPoint point)
{
     //将point转换为窗口坐标
     CRect rcWindow;
     GetWindowRect(&rcWindow);
     point.Offset(-rcWindow.left,-rcWindow.top);
    
     //按钮搜索
     for  ( INT  i=0;i<CountArray(m_cbButtonState);i++)
     {
         if  ((m_cbButtonState[i]&BUT_EXIST)&&(m_rcButton[i].PtInRect(point)))
         {
             //当前判断
             if  (m_cbNowButtonIndex==i)  return ;
    
             //清除状态
             if  (m_cbNowButtonIndex!=INVALID_BYTE)
             {
                 m_cbNowHotIndex[m_cbNowButtonIndex]=en_Normal;
             }
    
             //设置状态
             if  ((m_cbButtonState[i]&BUT_EXIST)&&(!(m_cbButtonState[i]&BUT_DISABLE)))
             {
                 m_cbNowButtonIndex=i;
                 m_cbNowHotIndex[i] = en_Hoven;
             }
    
             CDC *pDC = GetWindowDC();
             DrawTitleButton(pDC);
             ReleaseDC(pDC);
    
             return ;
         }
     }
    
     //清理焦点
     if  (m_cbNowButtonIndex!=INVALID_BYTE)
     {
         //设置变量
         m_cbNowButtonIndex=INVALID_BYTE;
         ZeroMemory(&m_cbNowHotIndex, sizeof  m_cbNowHotIndex);
    
         CDC *pDC = GetWindowDC();
         DrawTitleButton(pDC);
         ReleaseDC(pDC);
     }
    
     CDialog::OnNcMouseMove(nHitTest, point);
}

运行一下再看看,效果是不是出来了呢,按钮可以显示Hoven状态了,但是美中不足的是,鼠标移除窗口的时候,按钮不会更新状态,那就在增加一个WM_NCMOUSELEAVE消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void  CDialogEx::OnNcMouseLeave()
{
     //清理焦点
     if  (m_cbNowButtonIndex!=INVALID_BYTE)
     {
         //设置变量
         m_cbNowButtonIndex=INVALID_BYTE;
         ZeroMemory(&m_cbNowHotIndex, sizeof  m_cbNowHotIndex);
    
         CDC *pDC = GetWindowDC();
         DrawTitleButton(pDC);
         ReleaseDC(pDC);
     }
    
     CDialog::OnNcMouseLeave();
}

在看看效果,嗯,这次效果好多了。在添加鼠标按下的状态,添加WM_NCLBUTTONDOWN消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void  CDialogEx::OnNcLButtonDown( UINT  nHitTest, CPoint point)
{
     //将point转换为窗口坐标
     CRect rcWindow;
     GetWindowRect(&rcWindow);
     point.Offset(-rcWindow.left,-rcWindow.top);
    
     //按钮搜索
     for  ( INT  i=0;i<CountArray(m_cbButtonState);i++)
     {
         if  ((m_cbButtonState[i]&BUT_EXIST)&&(m_rcButton[i].PtInRect(point)))
         {
             //清除状态
             if  (m_cbNowButtonIndex!=INVALID_BYTE)
             {
                 m_cbNowHotIndex[m_cbNowButtonIndex]=en_Normal;
             }
    
             //设置状态
             if  ((m_cbButtonState[i]&BUT_EXIST)&&(!(m_cbButtonState[i]&BUT_DISABLE)))
             {
                 m_cbNowButtonIndex=i;
                 m_cbNowHotIndex[i] = en_Press;
             }
    
             CDC *pDC = GetWindowDC();
             DrawTitleButton(pDC);
             ReleaseDC(pDC);
    
             return ;
         }
     }
    
     //清理焦点
     if  (m_cbNowButtonIndex!=INVALID_BYTE)
     {
         //设置变量
         m_cbNowButtonIndex=INVALID_BYTE;
         ZeroMemory(&m_cbNowHotIndex, sizeof  m_cbNowHotIndex);
    
         CDC *pDC = GetWindowDC();
         DrawTitleButton(pDC);
         ReleaseDC(pDC);
     }
    
     CDialog::OnNcLButtonDown(nHitTest, point);
}

在运行一下看看,嗯,状态是有了,但是按下之后鼠标抬起的时候没有重置到之前的状态,那就再添加鼠标抬起的消息WM_NCLBUTTONUP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void  CDialogEx::OnNcLButtonUp( UINT  nHitTest, CPoint point)
{
     //将point转换为窗口坐标
     CRect rcWindow;
     GetWindowRect(&rcWindow);
     point.Offset(-rcWindow.left,-rcWindow.top);
    
     //按钮搜索
     for  ( INT  i=0;i<CountArray(m_cbButtonState);i++)
     {
         if  ((m_cbButtonState[i]&BUT_EXIST)&&(m_rcButton[i].PtInRect(point)))
         {
             //设置状态
             if  ((m_cbButtonState[i]&BUT_EXIST)&&(!(m_cbButtonState[i]&BUT_DISABLE)))
             {
                 switch  (i)
                 {
                 case  0:
                     SendMessage(WM_CLOSE);
                     break ;
                 case  1:
                     if  (IsZoomed())
                         SendMessage(WM_SYSCOMMAND, SC_RESTORE, MAKELPARAM(point.x, point.y));
                     else  SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(point.x, point.y));
    
                     break ;
                 case  2:
                     SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(point.x, point.y));
                     break ;
                 }
             }
    
             //设置变量
             m_cbNowButtonIndex=INVALID_BYTE;
             ZeroMemory(&m_cbNowHotIndex, sizeof  m_cbNowHotIndex);
    
             CDC *pDC = GetWindowDC();
             DrawTitleButton(pDC);
             ReleaseDC(pDC);
    
             return ;
         }
     }
    
     CDialog::OnNcLButtonUp(nHitTest, point);
}

在这里,你发现代码里面多了一个switch语句,这几句代码是发送窗口消息命令的,大家都知道,当鼠标按下最小化按钮的时候,窗口并没有立马最小化,而是鼠标抬起的时候在最小化的,所以,我们也在鼠标抬起的时候去响应 这些命令,在这里用到了一个API函数,SendMessage,大家一定要区分开SendMessage和PostMessage的区别,很多面试公司会考这个,这里我就不多说了。其次,发送 命令的时候,我用到了WM_SYSCOMMAND,这个也要和WM_COMMAND消息区别开,WM_SYSCOMMAND的消息种类就那么几个,如下,这是 winuser.h提供的WM_SYSCOMMAND参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
  * System Menu Command Values
  */
#define SC_SIZE         0xF000
#define SC_MOVE         0xF010
#define SC_MINIMIZE     0xF020
#define SC_MAXIMIZE     0xF030
#define SC_NEXTWINDOW   0xF040
#define SC_PREVWINDOW   0xF050
#define SC_CLOSE        0xF060
#define SC_VSCROLL      0xF070
#define SC_HSCROLL      0xF080
#define SC_MOUSEMENU    0xF090
#define SC_KEYMENU      0xF100
#define SC_ARRANGE      0xF110
#define SC_RESTORE      0xF120
#define SC_TASKLIST     0xF130
#define SC_SCREENSAVE   0xF140
#define SC_HOTKEY       0xF150
#if(WINVER >= 0x0400)
#define SC_DEFAULT      0xF160
#define SC_MONITORPOWER 0xF170
#define SC_CONTEXTHELP  0xF180
#define SC_SEPARATOR    0xF00F
#endif /* WINVER >= 0x0400 */
    
#if(WINVER >= 0x0600)
#define SCF_ISSECURE    0x00000001
#endif /* WINVER >= 0x0600 */
    
/*
  * Obsolete names
  */
#define SC_ICON         SC_MINIMIZE
#define SC_ZOOM         SC_MAXIMIZE
    
#endif /* !NOSYSCOMMANDS */


到现在为止,窗口的重绘就完成了,如果你有什么不懂的话,随时给我留言,下一篇我们在开始说一下重绘窗口的其他做法,这个可以做出更加炫丽的窗口样式。下一篇再见。


代码下载地址:http://download.csdn.net/detail/gym1039/6292463


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值