九、定制应用程序外观
1. 如果希望在应用程序窗口创建之前修改它的外观和大小,就应该在CMainFrame类的PreCreateWindow成员函数中进行;(只需要修改CREATETRUCT结构体中的相关成员变量就行)
//修改窗口大小
Cs.cx = 300;
Cs.cx =200;
//修改程序窗口风格
//如果想让窗口显示自己的标题,只需要将窗口的FWS_ADDTOTITLE样式去掉;
Cs.lpszName = http://www.sunxin.org;
Cs.style &=~FWS_ADDTOTITLE;
2. 在窗口创建之后修改
在窗口创建之后修改其外观,可以在框架类的OnCreate函数中添加具体的实现代码;
利用SetWindowLong,和GetWindowLong;
SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,
GWL_STYLE) &~WS_MAXIMIZEBOX);
3. 修改窗口的光标、图标和背景:在窗口创建前修改
在框架类的PreCreateWindow函数中编写一个自己的窗口类并注册;
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 = "sunxin.org";
wndcls.lpszMenuName = NULL;
wndcls.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
cs.lpszClass = "sunxin.org";//指定类名,得跟注册的名字一样
但凡以AFX开始的函数都是应用程序框架类函数,也是全局函数,在程序的所有类中都可以直接调用;
注意:在MFC程序中,如果想要修改应用程序窗口的图标,则应在框架类中进行,因为在框架窗口中才有标题栏,所以才能修改位于该标题栏上的图标;如果想要修改程序窗口的背景和光标,就应该在视类中进行;
所以得在视类的PreCreateWindow函数中添加
Cs.lpszClas = “sunxin.org”;
第二种方法:不需要重写整个窗口类,比较简单
//不需要重写整个框架类
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW |CS_VREDRAW,0,0,//光标和背景都为0
LoadIcon(NULL,IDI_WARNING));
4. 修改窗口的光标、图标、和背景:在窗口创建之后修改:OnCreate函数中
SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));
5,模拟动画图标:利用定时器和SetClassLong函数就可以完成这个功能;
6,加载图标资源
externCStyleApp theApp;
//LoadIcon函数的第一个参数为NULL,加载的是系统图标
//使用自定义图标,第一个参数应为应用程序的当前实例句柄
//MAKEINTERSOURCE宏将资源ID号转换为资源标识符字符串
m_hIcons[0]= LoadIcon(AfxGetInstanceHandle(),MAKEINTERSOURCE(IDI_ICON1));
//利用全部变量theapp,需要添加声明 extern C**App theApp;
m_hIcons[1]= LoadIcon(theApp.m_hInstance,MAKEINTERSOURCE(IDI_ICON2));
m_hIcons[2]=LoadIcon(AfxGetApp()->m_hinstance,MAKEINTERSOURCE(IDI_ICON3));
然后设置定时器:SetTimer(1,1000,NULL);
然后再为类添加定时器消息WM_TIMER的响应函数,并调用SetClassLong函数改变应用程序窗口的图标;
作为静态的局部变量,它将存放在程序的数据区中,而不是在栈中分配空间的;static
1. 工具栏编程
在工具栏中删除按钮:不要用delete,而是在按钮上按下鼠标左键,然后拖出工具栏就可以了;
2. 创建工具栏的方法有两种:
(一) 第一种方法:
1. 创建工具栏资源;
2. 构造CToolBar对象
3. 调用Create或者CreateEx函数创建windows工具栏,并把它与已创建的CToolBar对象关联起来;
4. 调用LoadToolBar函数加载工具栏资源;
(二) 第二种方法:
1. 构造CToolBar对象;
2. 调用Create或者CreateEx函数创建windows工具栏,并把它与已创建的CToolBar对象关联起来;
3. 调用LoadBitmap函数加载包含工具栏按钮的图像的位图;(该位图为Toolbar.bmp,里面有许多小图像,对应按钮)
4. 调用SetButtons函数设置样式,并把工具栏上的一个按钮与位图中的一个图像相关联;
3. MFC创建工具栏的过程
在框架类的OnCreate函数中;
MFC为我们自动创建的工具栏和主菜单的资源ID是一样的,也就是说,在MFC编程中,一个ID可以表示多种资源;
4. 创建自定义的工具栏
调用工具栏对象的EnableDockng函数允许工具栏停靠于客户区的任意位置;
框架类的EnableDocking函数,让主框架窗口可以被停靠;
最后调用的DockControlBar函数,可以让这个新工具栏停靠在主框架窗口上;
如何让工具栏显示和隐藏:
if (m_newToolBar.IsWindowVisible())
{
m_newToolBar.ShowWindow(SW_HIDE);
}
else
{
m_newToolBar.ShowWindow(SW_SHOW);
}
//让滚动条重新调整它的位置
RecalcLayout();
//让工具栏漂浮移动后显示停靠在主框架窗口上;
DockControlBar(&m_newToolBar);
也可以用一个函数来实现显示/隐藏工具栏
ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);
设置菜单复选标志:
为这个菜单添加一个UPDATE_COMMAND_UT消息响应函数
pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
5. 状态栏编程:在框架类中的OnCreate函数中;用CStatusBar类定义了一个m_wndStatusBar变量;
6. 状态栏的右下角称为状态指示器;
状态栏对象也是在框架类中定义的;
在调用状态栏对象Create函数创建状态栏后,接着调用SetIndicators函数设置状态栏指示器,其中用到一个数组参数:indicators;,这个数组在框架类的源文件定义的,
数组的元素其实就是ID(状态栏指示器),后面三个ID其实就是MFC预先为我们定义好的字符串资源ID;
//获取时间
CTime t = CTime::GetCurrentTime();
CString str = t.Format("%H:%M:%S");
//将它显示在状态栏上
m_wndStatusBar.SetPaneText(1,str);//1是索引
//不知道索引的情况下,可通过ID来得到相应的索引
CTimet = CTime::GetCurrentTime();
CStringstr = t.Format("%H:%M:%S");
intindex =0;
index= m_wndStatusBar.CommandToIndex(IDS_TIMER);
m_wndStatusBar.SetPaneText(index,str);
/*
//获取足够的宽度来显示时间
CTimet = CTime::GetCurrentTime();
CStringstr = t.Format("%H:%M:%S");
CClientDCdc(this);
CSizesz = dc.GetTextExtent(str);
intindex =0;
index= m_wndStatusBar.CommandToIndex(IDS_TIMER);
//把窗体风格,宽度再加大些
m_wndStatusBar.SetPaneInfo(index,IDS_TIMER,SBPS_NOBORDERS,sz.cx);
m_wndStatusBar.SetPaneText(index,str);
*/
7. 进度栏编程
在窗口中创建进度栏
先定义一个CProgressCtrl类型的成员变量:m_progress,然后在OnCreate函数中创建;
m_progress.Create(WS_CHILD | WS_VISIBLE,CRect(100,100,120,120),this,123);
//显示当前进度
m_progress.SetPos(50);
8. 在状态栏的窗格中创建进度栏
首先要获得该窗格的区域,然后将这个区域的大小作为进度栏的大小;GetItemRect函数
框架类的OnCreate函数是在响应框架窗口的WM_CREATE消息时候调用的;
为了避免我们自定义的这条消息与其他已有消息发生冲突,应用利用windows提供的一个常量:WM_USER,我们只需要加1就可以用了;(我们自定义的消息最好用UM_为前缀)
命令消息是用ON_COMMAND宏将消息与消息响应函数关联起来,而对于自定义的消息来说,是使用ON_MESSAGE宏来实现这一功能的;
编写状态栏最好在响应WM_PAINT的消息函数中:
CRect rect;
m_wndStatusBar.GetItemRect(2,&rect);
//判断是否已经创建进度栏
if (!m_progress.m_hWnd)
{
m_progress.Create(WS_CHILD | WS_VISIBLE|PBS_SMOOTH,rect,&m_wndStatusBar,123);
}
else
{
//把进度栏移动到目标矩形区域中
m_progress.MoveWindow(rect);
}
m_progress.SetPos(50);
自动增加步长,可在响应定时器消息中:
m_progress.StepIt();
14,在状态栏中显示鼠标当前位置(视类中实现)
视类没有包含框架类中的头文件,要引用框架类中定义的东西,必须得在视类中包含进来;
响应鼠标移动的消息
CStringstr;
str.Format("x=%d,y=%d",point.x,point.y);
//第一种要改m_wndStatusBar的权限
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
//或者用另外一个函数
//((CMainFrame*)GetParent())->SetMessageText(str);
//第三种方法,用GetMessageBar()返回状态栏对象的指针,从而不用改权限
//((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);
状态栏不属于视类窗口,它属于框架类窗口;
CMainFrame类派生于CFrameWnd类;
15,启动画面(利用组件Splash screen)
在CSplashWnd类的OnCreate函数中,可以看到它设置了一个定时器;