对窗口外观的修改

对窗口外观的修改


窗口的外观或者风格可以有类风格(CS_)和窗口风格(WS_),改变外观就是改变这两个风格。窗口风格是由一个CREATESTRUCT结构体作为API函数CreateWindow()参数确定的。


类风格是由一个WNDCLASS结构体在注册窗口类之后确定的。


而改变可以在窗口对象创建之前和之后改变。


A 窗口创建之前改变


在PreCreateWindow(CREATESTRUCT &cs)中修改,该函数是CWnd类的成员函数。

窗口风格:对于窗口风格只要修改cs的成员就可以实现。

类风格:但是对于由窗口类指定的那些诸如图标光标等类风格就不能由cs修改了,

因为他们是由WNDCLASS结构在注册的时候指定的,所以只能修改更底层的窗口类,并重新注册。

方法如下:

方法一

在PreCreateWindow函数中,定义一个WNDCLASS变量并注册,然后把cs.lpszclss成员赋

为该已注册类的窗口类名。例如:

PreCreateWindow(CREATESTRUCT &cs)

{

...

WNDCLASS wndcls;

wndcls.cbClsExtra=0;

wndcls.cbWndExtra=0;

wndcls.hbrBackgroud=(HBRUSH)GetStockObject(BLACK_BRUSH);

wndcls.hCursor=LoadCursor(NULL,IDC_HELP);

wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);

wndcls.hInstance=AfxGetInstanceHandle();

wndcls.lpfnWndProc=::DefWindowProc;

wndcls.lpszClassName="ncls" //!!指定新类的名字,在后面cs.lpszclss就用该名字!!

wndcls.lpszMenuName="";

wndcls.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&wndcls);

cs.lpszClass="ncls";

...

return TRUE;

}

对于单文档应用程序要修改背景和光标,应该在CView类的PreCreateWindow中去修改。

但是对于注册窗口类可以在任意一个窗口的PreCreateWindow函数都可以(只要那个窗口能在一开始就被创建)。

方法2

方法一要写大一段代码,如果仅仅是只要修改类风格/背景/光标/图标,就要重写所有代码,那么用上面的方法很麻烦,

MFC提供了一个相当方便的方式来修改风格/背景/光标/图标,就是使用AfxRigisterWnwClass()函数,该函数只修改风格/背景/光标/图标,返回值就是注册后的类名。

函数原类:

LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0 );

举列:

/*WNDCLASS wndcls;

wndcls.cbClsExtra=0;

wndcls.cbWndExtra=0;

wndcls.hbrBackgroud=(HBRUSH)GetStockObject(BLACK_BRUSH);

wndcls.hCursor=LoadCursor(NULL,IDC_HELP);

wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);

wndcls.hInstance=AfxGetInstanceHandle();

wndcls.lpfnWndProc=::DefWindowProc;

wndcls.lpszClassName="ncls" //!!指定新类的名字,在后面cs.lpszclss就用该名字!!

wndcls.lpszMenuName="";

wndcls.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&wndcls);*/

...

return TRUE;

}

同样对于单文档应用程序要修改背景和光标,应该在CView类的PreCreateWindow中去修改。

类似的方法如下:

CMyView::PreCreateWindow(CREATESTRUCT &cs)

{

...

cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,LoadCursor(NULL,IDC_HELP),(HBRUSH)GetStockObject(BLACK_BRUSH),LoadIcon(IDI_WARRING));

如果仅仅是要修改风格/背景/光标/图标中任意一个,这条语句效果等于下面的一段语句。

...

}

以上两种方法实质都是一样的,都是在窗口内存对象创建之前改变,也可以在窗口对象创建之后改变。

B、窗口对象创建之后改变


要在窗口创建之后改变外观可以在OnCreate函数中编写代码实现。

改变窗口风格:利用一个全局的API函数SetWindowLong(),它可以在窗口创建之后改变窗口的外观。


函数原型:

LONG SetWindowLong(

HWND hWnd,       // handle of window

int nIndex,      // offset of value to set

LONG dwNewLong   // new value

);

举例,改变框架窗口标题:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       ...

SetWindowLong(m_hWnd,GCL_STYLE,WS_OVERLAPPEDWINDOW);

       ...

}

也可以获取指定窗口的现有外观信息。

LONG GetWindowLong(

HWND hWnd,       // handle of window指定获取哪个窗口

int nIndex,      // offset of value to set指定要获取的类型

);

应用举例:

SetWindowLong(m_hWnd,GCL_STYLE,GetWindowLong(m_hWnd,GCL_STYLE)&~WS_MAXIMIZEBOX);//在现有窗口风格上取消某一风格。

改变类风格:利用一个全局的API函数SetClassLong, 它可以改变WNDCLASSEX结构体变量的值,这个函数的用法和


SetWindowLong很类似。

函数原型:

DWORD SetClassLong(

HWND hWnd,       // handle of window

int nIndex,      // index of value to change ,即要改变的对象的索引值

LONG dwNewLong   // new value

);

举例,改变视图窗口光标和背景:

int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       ...

SetClassLong(m_hWnd,GCL_HBRACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));

SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));

     ...

}

应用举例,让框架窗口图标在3个图标中不断变换


利用上面的方法可以实现不断改变的光标,达到动画的效果。

只要利用定时器和SetClassLong函数就可以完成。

每秒中调用一次SetClassLong。

方法步骤:

1、先做做好3个图标,然后把它们导入到资源中得到IDC_ICON1,IDC_ICON2,IDC_ICON3;

2、然后在CMainFram类中添加一个HICON 类型的数组m_hIcons[3],用来保存图标句柄。

3、然后在CMainFrame::OnCreate()中用LoadIcon()加载图标,加载自己定义图标的方法如下:

m_hIcons[0]=LoadIcon(AfxGetInstanceHandle(),MAKEINTSOURSE(IDC_ICON1));

解释:利用全局函数AfxGetInstanceHandle()获取当前实例句柄,MAKEINTSOURSE()是一个宏,用来把一个资源ID号转换为资源管理函数兼容的值,返回的是LPTSTR类型。

LoadIcon函数原形:

HICON LoadIcon(

HINSTANCE hInstance, // handle to application instance

LPCTSTR lpIconName   // icon-name string or icon resource

                       // identifier

);

m_hIcons[1]=LoadIcon(AfxGetInstanceHandle(),MAKEINTSOURSE(IDC_ICON2));

m_hIcons[2]=LoadIcon(AfxGetInstanceHandle(),MAKEINTSOURSE(IDC_ICON3));

获取当前实例句柄还有两种方法:theApp.m_hInstance,AfxGetApp()->m_hInstance;


实际上AfxGetApp()获取的就是&theApp,所以这两种方式实质是一样的。


用这两种方法的依据是,所有的CWinApp类中有一个成员m_hInstance保存了WinMain()函数的hInstance句柄参数。


所以上面的语句也可以用下面的语句代替:

m_hIcons[1]=LoadIcon(theApp.m_hInstance,MAKEINTSOURSE(IDC_ICON2));

m_hIcons[2]=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTSOURSE(IDC_ICON3));

4、添加定时器


SetTimer(1,1000,NULL);//


第3个参数是定时器的消息处理函数,为NULL的时候WM_TIMER被放到应用程序消息队列当中去由CWnd对象处理.


设置定时器的函数原型:


UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );


参数说名:


Return Value


The timer identifier of the new timer if the function is successful. An application passes this value to the KillTimer member function to kill the timer. Nonzero if successful; otherwise 0.


Parameters


nIDEvent


Specifies a nonzero timer identifier.


nElapse


Specifies the time-out value, in milliseconds.


lpfnTimer


Specifies the address of the application-supplied TimerProc callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the application’s message queue and handled by the CWnd object.


有个细节要注意,为了不让系统默认的图标在一开始就出现,可以在OnCreate函数中就改变窗口图标:


SetClassLong(m_hWnd,GCL_ICON,m_hIcons[1]);//

5、然后给框架类添加WM_TIMER消息相应函数OnTimer用SetClassLong()设置图标

void CMainFrain::OnTimer(UINT nIDEven)


{


static int i=0;


SetClassLong(m_hWnd,GCL_ICON,m_hIcons[i]);//随着每次相应WM_TIMER消息i不断在0~2之间变化,从而图标也不断变化


i=++i%3;


CFrameWnd::OnTimer(nIDEvent);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值