9.1修改应用程序窗口的外观
对于MFC AppWizard生成的应用程序,我们可以在应用程序窗口创建之前修改,也可以在该窗口创建之后进行。
9.1.1在窗口创建之前修改
新建一个单文档应用程序,取名Style,如果想在应用程序创建之前修改它的外观和大小,就应该在框架类的PreCreateWindow成员函数中进行。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx=300;
cs.cy=200;
return TRUE;
}
PreCreateWindow是一个虚函数,可以利用多态性调用子类对象的PreCreateWindow函数。
CREATESTRUCT结构中的字段与CreateWindowEx函数中的参数是完全一致的,只不过顺序相反而已。因为CREATESTRUCT参数为引用类型,可以在子类对象中修改这个参数成员变量的值。
当MFC底层代码调用CreateWindowEx函数去创建窗口时,他就会使用改变后的参数值去创建这个窗口。这里该变量窗口的长度和宽度。如图。
如果想修改应用程序窗口的坐标,可以修改CREATESTRUCT结构体中lpszName成员的值来实现。
cs.lpszName=“vc++”;
但是运行后,发现应用程序标题并没有发生改变。
这个Style应用程序是一个单文档应用程序,在单文档的界面中,程序默认的窗口样式是WS_OVERLAPPEDWINDOW和FWS_ADDTOTITLE,FWS_ADDTOTITLE是MFC特定的一种样式,指示框架将文档标题添加到窗口标题之上,如果想让窗口显示自己的标题,只需要将窗口的FWS_ADDTOTITLE样式去掉即可。
cs.style &= ~FWS_ADDTOTITLE;
或者cs.style =cs.style & ~FWS_ADDTOTITLE;
或者cs.style =WS_OVERLAPPEDWINDOW;
如图。
9.1.2在窗口创建之后修改
窗口创建之后可以利用SetWindowLong函数进行修改,为了改变窗口类型,该函数第二个参数为GWL_STYLE,第三个参数指定新的窗口类型。在窗口创建之后改变其外观,可以在框架类OnCreate函数中实现。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);
return 0;
}
运行程序,发现窗口标题栏上面去掉了文本标题。如图。
如果在已有的窗口类型上面进行修改,首先要获得该窗口类型,利用GetWindowLong函数。
LONG GetWindowLong(
HWND hWnd, // handle of window
int nIndex // offset of value to retrieve
);
如果将第二个参数设定为GWL_STYLE,获取指定窗口的类型。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
……
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE)& ~WS_MAXIMIZEBOX);
return 0;
}
运行,发现右上角最大化框变灰了,窗口就不能放大。如图。
9.2修改窗口的光标、图标和背景。
9.2.1在窗口创建之前修改
图标、光标和背景是在设计窗口类时指定的,因此在框架类的PreCreateWindow函数中编写自己的窗口类并注册。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
WNDCLASS wndcls;
//类的额外内存和窗口的额外内存都设置为0
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
//背景设置为黑色
wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
//使用系统光标,第一个参数为NULL,使用系统帮助光标
wndcls.hCursor=LoadCursor(NULL,IDC_HELP);
//使用系统错误的图标
wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
//调用该函数,获取当前应用程序实例句柄
wndcls.hInstance=AfxGetInstanceHandle();
//调用默认的窗口过程函数,不做特殊消息的处理
wndcls.lpfnWndProc=::DefWindowProc;
//类的名称和菜单的名称、窗口类的类型是水平和垂直重绘
wndcls.lpszClassName="vc++";
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
//使用刚刚注册的窗口类
cs.lpszClass="vc++";
return TRUE;
}
运行程序,发现只有图标变化了,光标和背景没有变化。如图。
因为只有图标是在框架类窗口上,没有被视类覆盖。因此对于光标和背景的修改需要在视类中修改。
因为窗口类已经注册了,所以创建视类窗口时,可以直接使用该窗口类。
BOOL CStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.lpszClass="vc++";
return CView::PreCreateWindow(cs);
}
运行结果如图。
重写窗口类这个方法很麻烦,MFC提供了一个全局函数:AfxRegisterWndClass函数来设定窗口的类型、光标、背景和图标。
LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0 );
将前面重写窗口类的方法的代码注释起来。
在框架类中:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));
return TRUE;
}
只设置一个警告类型的图标
在视类中:
BOOL CStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0);
return CView::PreCreateWindow(cs);
}
设置一个十字形状的光标,背景设置为黑色。
但是,如果均用默认的0。光标就是箭头,背景透明,图标就是Windows Logo。
9.2.2在窗口创建之后修改
这时可以利用全局API函数:SetClassLong。
DWORD SetClassLong(
HWND hWnd, // handle of window
int nIndex, // index of value to change
LONG dwNewLong // new value
);
第二个参数是属性的索引。
GCL_HBRBACKGROUND:设置新的背景画刷。
GCL_HCURSOR:设置新的光标。
GCL_HICON:设置新的图标。
GCL_STYLE:设置新的窗口样式。
第三个参数:要设置的新的属性值。
首先在框架类的OnCreate函数中设置图标:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));
return 0;
}
由于视类没有OnCreate函数,所以需要添加WM_CREATE消息相应函数。
int CStyleView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetWindowLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));
SetWindowLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));
return 0;
}
修改窗口的光标和背景。运行结果与前面是一样的。