您的位置:首页 > 编程语言 > C语言/C++

孙鑫VC++深入详解(8):定制应用程序外观

2014-04-30 17:18 337 查看
1、修改窗口的外观

如果希望在窗口创建之前修改它的外观和大小,可以重写窗口类的虚函数PreCreateWindow(),在这个函数中进行修改:PreCreateWindow函数的参数CREATESTRUCT结构中的成员与CreateWindow(CreateWindowEx)的参数相同,可以通过修改这个参数的成员来修改窗口的外观。eg:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	......

	//修改窗口大小
	cs.cx = 1024;
	cs.cy = 800;

	//修改窗口标题
	cs.style &= ~FWS_ADDTOTITLE;
	cs.lpszName = _T("VC++学习");

	return TRUE;
}
在单文档界面程序中,默认窗口样式是WS_OVERLAPPENWINDOW | FWS_ADDTOTITLE,FWS_ADDTOTITLE指示将默认文档标题添加到窗口标题上, 如果想让窗口显示自定义的文档标题,应去掉窗口的FWS_ADDTOTITLE样式:cs.style = WS_OVERLAPPEDWINDOW 或cs.style &= ~FWS_ADDTOTITLE;

需要注意的地方是对话框窗口不会执行PreCreateWindow()函数:一般的窗口的创建是使用CWnd::Create函数,这个函数在创建窗口之前调用了PreCreateWindow函数,并且允许在创建创建之前在PreCreateWindow注册一个拥有自定义窗口样式的新的窗口类,来创建一个拥有自定义类名新的窗口。而对话框是通过CreateDialogIndirect来创建的,在这当中并没有调用PreCreateWindow函数,重载的PreCreateWindow函数根本就不被执行,因此在这个函数里修改对话框的窗口类是没有用的。

如果想要在窗口创建之后修改其外观,可以在OnCreate()中调用SetWindowLong()函数修改窗口的属性。eg:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	......

	SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);//去掉窗口标题栏上默认文档标题

	return 0;
}
如果是在窗口已有类型的基础上进行一些修改的话,那么应先获得这个窗口的现有属性类型,这可以利用GetWindowLong()函数实现,eg:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	......

	SetWindowLong(m_hWnd, GWL_STYLE,GetWindowLong(m_hWnd, GWL_STYLE)&~WS_MAXIMIZEBOX);//禁用最大化按钮

	return 0;
}

2、修改窗口的光标、图标、背景

在窗口创建之前修改:

方法1、

窗口的类型和大小,是在创建窗口的时候设定的。而窗口的光标、图标、背景是在设计窗口类时指定的。我们可以在PreCreateWindow()函数中编写一个自己的窗口类并注册,然后将PreCreateWindow()参数的成员lpszClass赋值为自定义的窗口类的名称,让随后创建的窗口按照我们编写的窗口类去创建。eg:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: 在此处通过修改

	WNDCLASS wndcls;
	wndcls.cbClsExtra = 0;//类的额外内存
	wndcls.cbWndExtra = 0;//窗口的额外内存
	wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);//设置窗口背景为黑色
	wndcls.hCursor = LoadCursor(NULL, IDC_HELP);//设置窗口光标为系统帮助光标
	wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);//设置窗口图标为系统错误图标	
	wndcls.hInstance = AfxGetInstanceHandle();//设置当前应用程序句柄
	wndcls.lpfnWndProc = ::DefWindowProc;//设置窗口过程
	wndcls.lpszClassName = _T("sunxin");//设置类的名称
	wndcls.lpszMenuName = NULL;//菜单资源的名称
	wndcls.style = CS_HREDRAW | CS_VREDRAW;//设置类的类型,水平重绘和垂直重绘
	RegisterClass(&wndcls);//注册窗口类

	cs.lpszClass = _T("sunxin");

	return TRUE;
}
AfxGetInstanceHandle()函数可以获得当前应用程序实例句柄。

这里在设置窗口类的窗口过程为默认窗口过程的时候应使用全局函数名::DefWindowProc,因为CWnd有一个成员函数DefWindowProc()。

单文档界面程序的菜单不是在设计窗口类的时候创建的,因此,在这里将窗口类的菜单设为NULL不会影响窗口菜单的创建。

需要注意的地方是:以上代码只会修改窗口的图标,而不会修改窗口的光标和背景,因为上面代码是在框架类窗口中进行的,视类窗口始终覆盖在框架类窗口之上,所以如果想要修改窗口的光标和背景则应该在视类窗口中设置,而这时,因为我们自定义的窗口类已经在框架类中注册完成了,所以这里可以直接拿来使用:

BOOL CtestView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或样式
	cs.lpszClass = _T("sunxin");

	return CView::PreCreateWindow(cs);
}

方法2、

MFC提供了一个全局函数AfxRegisterWndClass(),用来设置窗口的类型、光标、背景、画刷,它的返回值就是新注册之后的类名,可以将这个返回值作为随后创建窗口时所依赖的类。函数原型:

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

eg:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: 在此处通过修改

	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));

	return TRUE;
}

BOOL CtestView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改CREATESTRUCT cs 来修改窗口类或样式
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,\
		           LoadCursor(NULL, IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0);

	return CView::PreCreateWindow(cs);
}
在窗口创建之后修改:

SetClassLong() 用来重置指定窗口所属窗口类的WNDCLASSEX(WNDCLASS的扩展)结构体中指定数据成员,可以实现在窗口创建完成之后修改窗口的背景画刷、光标、图标、窗口样式, 函数原型:

DWORD WINAPI SetClassLong(
  _In_  HWND hWnd,
  _In_  int nIndex,
  _In_  LONG dwNewLong
);

hWnd为指定窗口。

nIndex可以为以下值:GCL_HBRBACKGROUND 设置新的背景画刷


GCL_HCURSOR 设置新的光标

GCL_HICON 设置新的图标

GCL_STYLE 设置新的窗口样式

dwNewLong为要设置的新值。

eg:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	......

	SetClassLong(m_hWnd, GCL_HICON, (LONG)LoadIcon(NULL,IDI_ERROR));

	return 0;
}

int CtestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));
	SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));

	return 0;
}
3、其它

一个文件中要想使用另一个文件中定义的全局变量,必须先声明这个变量是在外部定义的:extern CString g_strExePath;

MFC提供了一个全局函数AfxGetApp(),可以获得应用程序对象的指针,当前应用程序对象的成员变量m_hInstance为当前应用程序实例句柄。

如果希望把某个数值始终限定在一个范围内,最好的办法就是进行“取模(取余)”运算%,例如希望某个变量的值始终在0—10之间变化,则把这个变量对11“取模”即可。

4、工具栏编程

工具栏通常是把常用的菜单命令集合起来,以按钮的形式提供给用户使用,对应MFC类为CToolBar,派生于CControlBar控制条类,工具栏属于一个窗口 。

添加工具栏上的按钮可以直接在工程资源视图中的ToolBar资源中进行绘制,将其ID设为与指定的菜单按钮ID相同即可;添加工具栏上的分隔符可以直接拖动指定按钮一点距离后再松开;删除工具栏上按钮可以直接将其拖出工具栏即可。

单文档MFC应用程序的框架类中有一个成员变量m_wndToolBar,即为程序的工具栏对象,可以参考框架类OnCreate()中创建工具栏的方法创建一个工具栏。

框架类的成员函数CFrameWnd::ShowControlBar() 可以用来隐藏或显示指定的控制条,如工具栏。

5、状态栏编程

单文档MFC应用程序的框架类中有一个成员变量m_wndStatusBar,即为程序的工具栏对象,对应MFC类为CStatusBar,其同样派生于CControlBar控制条类。

状态栏的成员函数GetItemRect()可以获得状态栏上指定窗格的矩形区域。

状态栏的成员函数SetWindowText()可以设置状态栏上第一个窗格上的文本。

框架类CFrameWnd的成员函数SetMessageText()可以设置其状态栏上第一个窗格的文本。

框架类CFrameWnd的成员函数GetMessageBar()可以获得其状态栏对象的指针。

CWnd::GetDescendantWindow(int nID, BOOL bOnlyPerm = FALSE)可以根据指定ID获得其子孙窗口,其第二个参数用来指定返回的窗口能否是一个临时窗口:FALSE为可以返回临时窗口,TRUE为只返回持久的窗口。

6、进度栏编程

进度栏对应的MFC类是CProgressCtrl,其派生于CWnd,成员函数Create()用来创建一个进度栏控件,函数原型:

virtual BOOL Create(
   DWORD dwStyle,   //样式,除窗口样式外还包括PBS_VERTICAL(垂直显示)、PBS_SMOOTH(平滑进度条)
   const RECT& rect,//大小和位置
   CWnd* pParentWnd,//父窗口
   UINT nID         //ID
);

成员函数SetPos()可以设置进度栏的进度。

成员函数StepIt()使进度栏按照一定的步长增长。

成员函数SetStep()用来设置步长。

成员函数SetRange()用来设置进度栏的范围,默认情况下为0—100。

WM_USER是一个常量,小于这个常量的值都是windows系统保留的消息值,自定义消息值时,通常是用WM_USER加上一个数值,避免与windows系统消息冲突。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: