MFC原创教程:5.0 Style 窗口风格

来源:互联网 发布:2017运动手环推荐知乎 编辑:程序博客网 时间:2024/05/02 02:05

VC++/MFC Window编程原创教程目录

1:窗口创建之前改变外观
修改大小、标题,代码添加在: BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 if( !CFrameWndEx::PreCreateWindow(cs) )
  return FALSE;
 // TODO: 在此处通过修改
 //  CREATESTRUCT cs 来修改窗口类或样式
 cs.cx=800; //修改宽度
 cs.cy=800;

 cs.style &= ~FWS_ADDTOTITLE; //取反减去“或”运算;默认cs.style=WS_OVERLAPPEDWINDOW || FWS_ADDTOTITLE(增加文档标题到窗口标题)
 cs.lpszName="窗口标题修改";

 return TRUE;
}

2:窗口创建之后改变外观。
代码添加在CMainFrame::OnCreate (该函数先调用了基类,所以创建了窗口了)
 //SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);
 SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE) & ~WS_MAXIMIZEBOX);
 //改变窗口属性。参数(窗口句柄,设一新的风格,替换的值:获取旧分割“减去”窗口最大化属性)

3:使用窗口类修改。
代码添加在MainFrame::PreCreateWindow(把之前写的代码注释了吧)
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 if( !CFrameWndEx::PreCreateWindow(cs) )
  return FALSE;
 // TODO: 在此处通过修改
 //  CREATESTRUCT cs 来修改窗口类或样式 

 WNDCLASS wndcls; //设计窗口类
 wndcls.cbClsExtra=0;
 wndcls.cbWndExtra=0;
 //额外空间暂不需要http://topic.csdn.net/u/20080304/15/c9c072d3-a996-4f20-90cd-817bc13cc8d7.html
 wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //背景颜色
 wndcls.hCursor=LoadCursor(NULL,IDC_HELP); //光标。NULL表选用标准。
 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
 wndcls.hInstance=AfxGetInstanceHandle(); //获取应用程序的句柄
 wndcls.lpfnWndProc=::DefWindowProc; //窗口过程。::表调用全局API函数。
 wndcls.lpszClassName="类名字";
 wndcls.lpszMenuName=NULL;  //单文档EXE已经默认加载菜单了,此处可为NULL。
 wndcls.style=CS_HREDRAW | CS_VREDRAW; //窗口类类型。水平重画 | 垂直重画

 RegisterClass(&wndcls); //注册窗口类
 return TRUE;
}

//因为VIEW覆盖在框架类上,所以使用窗口类要在VIEW中使用。
BOOL CStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: 在此处通过修改
 //  CREATESTRUCT cs 来修改窗口类或样式
 cs.lpszClass="类名字";
 return CView::PreCreateWindow(cs);
}
第3步的代码其实只要用一行代码就能代替, 代码放在:CStyleView::PreCreateWindow
cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,LoadCursor(NULL,IDC_HELP),(HBRUSH)GetStockObject(BLACK_BRUSH), LoadIcon(NULL,IDI_ERROR));//若cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);,则得一个透明窗口,但VS2010貌似不是这样。

4:循环变化icon图标。
右键点击资源面板的Style.rc--添加资源--导入--下拉列表选择图标文件--选择3个ico格式的文件导入。
在CMainFrame添加私有数组HICON m_hIcon[3],使其分别成为3 个ICO文件关联变量。
在CMainFrame::OnCreate添加以下代码:
 m_hIcon[0]=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));//加载图标。参数(三种方式获取当前程序句柄:之前是使用标准图标故此参数不用设置,图标字符串指针:MAKEINTRESOURCE宏将一个整型值转换成和资源管理函数兼容的资源类型 )
 m_hIcon[1]=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2)); //其它类的变量,需要extern CStyleApp theApp;
 m_hIcon[2]=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));
SetTimer(1,1000,NULL);//定时器(标识,毫秒,回调函数)

添加一个Timer消息
void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 static int index=0; //作为数组下标
 SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcon[index]); //改变窗口图标
 index=++index%3; //0~2循环公式
 CFrameWndEx::OnTimer(nIDEvent);
}

参考:http://blog.sina.com.cn/s/blog_69e905cd0100kk53.html

5.1:显示新工具栏

资源视图--Toolbar,图标ID号与对应菜单栏的选项ID相同。在菜单(IDR_MAINFRAME_256)添加一个ID号为IDM_TEXT的菜单项,添加按钮消息,弹出MessageBox,然后在工具栏视图画个新的工具(若没有关联消息,则是灰色显示),修改其ID为IDM_TEXT。运行时,两处的点击效果一样。(画图要使用:图像编辑器)删除按钮的方法:将按钮拖离工具栏,用Delete键不管用,Delete只是删除了按钮上的图像;插入分隔符的方法(S2010貌似不能实现,暂时找不到解决方法):横向右拖动按钮一定距离,就会插入分隔符,反方向再拖一下,就删除分隔符了。
VS2010的CMFCToolbar实现真彩色工具栏:http://blog.sina.com.cn/s/blog_6d4b374e01015hhd.html

插入新的ToolBar(IDR_TOOLBAR1),画三、四个图标。
新工具栏的显示方法1:教程里使用的是CToolBar,但在VS2010不奏效,需要用到CMFCToolBar。http://www.cnblogs.com/luoshupeng/archive/2011/08/15/2139645.html

首先在MainFrm.h,加入一个CMFCToolBar变量

 CMainFrame::OnCreate末端添加以下代码:

if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_RIGHT | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS | !m_newToolBar.LoadToolBar(IDR_TOOLBAR1))  //该OnCreate函数开头有创建主工具栏的代码,模仿即可。
 {
  TRACE0("未能创建工具栏\n");
  return -1;      // 未能创建
 }
 m_newToolBar.EnableDocking(CBRS_ALIGN_ANY); //设置工具栏可以停靠(任意地方)
 DockPane(&m_newToolBar); //工具栏停靠在主框架窗口上
//VS2010的工具栏要浮动,听说是要用到FloatPane(),但我不知道后面怎么搞了,工具栏都是默认浮动。。。

5.21:显示、隐藏工具栏

菜单栏资源的视图子菜单添加一个菜单项:新工具栏,ID修改为:IDM_VIEW_NEWTOOL。右键--添加处理函数(COMMAND,CMainFrame)。
void CMainFrame::OnViewNewtool()
{
 // TODO: 在此添加命令处理程序代码
 if(m_newToolBar.IsWindowVisible())
  m_newToolBar.ShowWindow(SW_HIDE);
 else
  m_newToolBar.ShowWindow(SW_SHOW);
 //RecalcLayout(); //重新调整。经测试,VS2010好像不需要这段代码
 DockPane(&m_newToolBar); //VC6.0使用的代码是DockControlBar(&m_newToolBar);
ShowPane(&m_newToolBar,!m_newToolBar.IsWindowVisible(),0,0); //VS2010显示工具栏的另一种方法(前面代码都注释掉)。VC6.0代码是:ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);
http://technet.microsoft.com/zh-cn/library/bb983173(v=vs.110).aspx
}

5.22:添加复选标记
右键点击 菜单栏资源的视图子菜单 新工具栏--添加事件处理--(UPDATE_COMMAND_UI  ,CMainFrame)
void CMainFrame::OnUpdateViewNewtool(CCmdUI *pCmdUI)
{
 // TODO: 在此添加命令更新用户界面处理程序代码
 pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
}

5.31:状态栏右下角窗格。
资源视图--StringTable-StringTable-添加(IDS_TIME,时间)(IDS_PROGRESS,进度栏)
CMainFrame::OnCreate


(在MainFrm.h可以找到m_wndStatusBar,看看他的引用)
5.311:显示系统时间

 在CMainFrame::OnTimer(之前已经添加过这个消息了)添加以下代码:
 CTime t=CTime::GetCurrentTime(); //获取系统时间
 CString str=t.Format("%H:%M:%S"); //格式化输出
 CClientDC dc(this);
 CSize sz=dc.GetTextExtent(str); //为了获取宽度
 m_wndStatusBar.SetPaneInfo(1,IDS_TIME,SBPS_NORMAL,sz.cx); //设置区域宽度
 m_wndStatusBar.SetPaneText(1,str); //显示时间

 


5.312:进度栏
类似5.1的新工具栏变量创建方法,加上:CProgressCtrl   m_progress;  //进度条控件
这一小节主要是学“用户消息”。首先在MainFrm.h定义一个消息(加在#pragma once之后)
#define UM_PROGRESS  WM_USER+1   //UM约定为用户的消息,WM是系统的消息,系统定义消息的值在WM_USER以下,故用户消息取值为...然后是消息响应函数原型的声明
afx_msg void OnProgress();


最后是在CPP加上消息映射和函数图片
void CMainFrame::OnProgress() //VS2010需加两参数(WPARAM wParam,LPARAM lParam)
{
 CRect rect; //用来接收右下角窗格的矩形
 m_wndStatusBar.GetItemRect(2,&rect);
 m_progress.Create(WS_CHILD | WS_VISIBLE,
  rect,&m_wndStatusBar,123); //创建窗格
 m_progress.SetPos(50);
}
以上代码不能在VS2010生效,详见:http://blog.163.com/chenpeijie0_0/blog/static/183094571201161304437752/

实现效果:

但当窗口发生重绘,进度栏并不会随窗格移动(造成错位),完善方法:添加WM_POINT消息
void CMainFrame::OnPaint()
{
 CPaintDC dc(this); // device context for painting
 // TODO: 在此处添加消息处理程序代码
 CRect rect; 
 m_wndStatusBar.GetItemRect(2,&rect);
 if(!m_progress.m_hWnd)
  m_progress.Create(WS_CHILD | WS_VISIBLE,
   rect,&m_wndStatusBar,123);
 else
  m_progress.MoveWindow(rect); //移动进度条
 m_progress.SetPos(50);
 // 不为绘图消息调用 CFrameWndEx::OnPaint()
}