孙鑫视频教程第九课——工具栏、状态栏、启动画面

来源:互联网 发布:买一个域名要多少钱 编辑:程序博客网 时间:2024/05/01 10:26
  

       如何修改MFC AppWizard向导生成的框架程序的外观和大小,修改图标、光标、背景的三种方法。如何增加和删除工具栏按钮,如何给应用程序增加工具栏,如何显示和隐藏工具栏。定制状态栏,在状态栏中添加时钟显示,CTime类及其用法。在状态栏中添加进度条(主窗口产生后立即产生进度条的巧妙思想,不能在OnCreate函数中直接处理,要用到自定义消息的方法)。鼠标坐标显示,在CView中获取状态栏对象的几种方式。如何为应用程序添加启动画面。

1.修改窗口的标题和大小:主要在cmainframe类中的precreatewindow()函数中来完成,代码如下:

         cs.cx = 800;//对窗口的宽度修改cs.cy = 600;//对窗口的高度修改cs.style &= ~FWS_ADDTOTITLE;//去掉一种类型,与下面的语句等同//cs.style = cs.style & ~FWS_ADDTOTITLE;//cs.style = WS_OVERLAPPEDWINDOW;//与上语句作用等同cs.lpszName = TEXT("http://www.sunxun.org");//对窗口标题的修改,只有经过上面的语句才可以显示自己的标题!


2.修改窗口的图标、光标和背景:注意:单文档的view类总是覆盖在框架类的上面,所以对图标的修改需要在cmainframe类中去修改,而对光标和背景的修改需要在view类中去修改!而又分为在窗口创建之前的修改和在窗口创建之后的修改:

a.在窗口创建之前对窗口图标的修改需要在cmainframe类中的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 = TEXT("sunxin.org");wndcls.lpszMenuName = NULL;wndcls.style = CS_HREDRAW | CS_VREDRAW;//是窗口类的类型,而不是窗口的类型RegisterClass(&wndcls);cs.lpszClass = TEXT("sunxin.org");//这个一定要,要不然就不可以按照所写的类进行修改,在框架类中修改图标!    //不用编写整个窗口类来修改窗口图标cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, 0, 0, LoadIcon(NULL, IDI_WARNING));cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);

b.在窗口创建之后对窗口图标的修改需要在cmainframe类中的oncreate()函数中去完成:

      //在窗口创建之后对窗口的修改SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);//改变指定窗口的属性SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) &~ WS_MAXIMIZEBOX);//先获取窗口的属性,再修改窗口的属性SetClassLong(m_hWnd, GCL_HICON, (LONG)LoadIcon(NULL, IDI_ERROR));

c.在窗口创建之前对窗口光标和背景的修改需要在cview类中的precreatewindow()函数中去完成:

       cs.lpszClass = TEXT("sunxin.org");//在view类中修改光标和背景//不用编写整个窗口类来修改窗口光标和背景cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, LoadCursor(NULL, IDC_CROSS), (HBRUSH)GetStockObject(BLACK_BRUSH), 0);*/cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);

d.在窗口创建之后对窗口光标和背景的修改需要在cview类中的oncreate()函数中去完成:

//在窗口创建之后对窗口背景和光标的修改SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(BLACK_BRUSH));SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_HELP));

3.让图标不断变换的功能的完成:需要在cmainframe类中的oncrea()函数中设置一个计时器:

SetTimer(1, 1000, NULL);//设置一个计时器

需要添加几个ico图标,然后在oncreate()函数中加载其图标:

//创建一个不断变换的图标m_hIcons[0] = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON1));//第一种获取程序句柄的方法,后面的函数主要是将id号转化为字符串    m_hIcons[1] = LoadIcon(theApp.m_hInstance, MAKEINTRESOURCE(IDI_ICON2));//第二种获取程序句柄的方法m_hIcons[2] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON3));//第三种获取程序句柄的方法m_hIcons[3] = LoadIcon(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_ICON4));SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[0]);//将第一幅图标设置为窗口图标

还需要添加一个计时器的消息响应函数:ontimer(),然后在ontimer()函数中完成其功能:

void CMainFrame::OnTimer(UINT_PTR nIDEvent){// TODO: 在此添加消息处理程序代码和/或调用默认值    static int index = 1;//声明为静态的变量SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);//对窗口图标的改变index = ++index % 4;//让index在0--2范围内不断变化CFrameWnd::OnTimer(nIDEvent);}

4.创建一个新的工具栏:(工具栏也是一个窗口)这个创建类同与菜单栏的创建:要创建新的资源,在加载资源:

//创建一个新的工具栏if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_RIGHT| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||!m_newToolBar.LoadToolBar(IDR_TOOLBAR1)){TRACE0("未能创建工具栏\n");return -1;      // 未能创建}m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);//让工具栏可以停靠DockControlBar(&m_newToolBar);//让工具栏可以被停靠于框架窗口上

另外还需要注意的两点就是:在工具栏上添加分割符只需要将按钮拖动一下就可以;删除工具栏上的按钮时,如果只按delete的话,只是删除按钮上面的图片,而删除不了按钮,只有将按拖出工具栏才可以将这个按钮彻底删除!

5.让工具栏隐藏和显示:通过菜单项的消息函数来响应:

void CMainFrame::OnNewTool(){// TODO: 在此添加命令处理程序代码//第一种显示工具栏的方法//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()函数来实现:

void CMainFrame::OnUpdateNewTool(CCmdUI *pCmdUI){// TODO: 在此添加命令更新用户界面处理程序代码pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());//为菜单项添加复选标记}

6.状态栏的修改:

a.在状态栏上面添加项目:只需要在string table 中创建其ID号和在cmainframe()的实现文件中对其ID号的声明即可!

static UINT indicators[] ={ID_SEPARATOR,           // 状态行指示器IDS_TIMER,      //在状态栏上面添加两项内容,需要在这里声明其ID号IDS_PROGRESS,ID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,};

b.在状态栏上的时钟处显示系统时间:在oncreate()函数中完成

//让状态栏上面的时钟处显示系统时间CTime t = CTime::GetCurrentTime();//返回一个系统时间CString str = t.Format("%H:%M:%S");CClientDC dc(this);CSize sz = dc.GetTextExtent(str);//获取显示文本字体的高度和宽度int index = 0;index = m_wndStatusBar.CommandToIndex(IDS_TIMER);//通过ID号来获取索引号m_wndStatusBar.SetPaneInfo(index, IDS_TIMER, SBPS_NORMAL, sz.cx);//对状态栏上的窗格的改变!m_wndStatusBar.SetPaneText(index, str);//对状态栏上项目进行设置文本

c.让本来静止的时间动起来:在ontimer()函数中完成:

void CMainFrame::OnTimer(UINT_PTR nIDEvent){// TODO: 在此添加消息处理程序代码和/或调用默认值        //让静止的时间动起来CTime t = CTime::GetCurrentTime();//返回一个系统时间CString str = t.Format("%H:%M:%S");CClientDC dc(this);CSize sz = dc.GetTextExtent(str);//获取显示文本字体的高度和宽度m_wndStatusBar.SetPaneInfo(1, IDS_TIMER, SBPS_NORMAL, sz.cx);//对状态栏上的窗格的改变!m_wndStatusBar.SetPaneText(1, str);//对状态栏上项目进行设置文本CFrameWnd::OnTimer(nIDEvent);}

7.进度栏的创建:

a.首先需要在cmainframe类的头文件中添加一个进度栏的对象:CProgressCtrl m_progress

//创建水平进度栏//m_progress.Create(WS_CHILD | WS_VISIBLE, CRect(100, 100, 300, 120), this, 123);//m_progress.SetPos(50);//设置进度栏的位置//创建垂直进度栏    m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_VERTICAL, CRect(100, 100, 120, 300), this, 123);m_progress.SetPos(50);

b.将进度栏添加到状态栏上面去:由于消息不能在oncreate()函数中响应,所以需要重新定义一个消息响应函数:首先在cmainframe类的头文件中定义一个消息:#define UM_PROGRESS WM_USER+1  //定义一个消息;然后消息函数原型的声明:afx_msg LRESULT OnProgress(WPARAM, LPARAM);//消息响应函数原型声明(此函数原型的声明不同于vc6.0,需要注意!);还有在oncreate函数中的消息传递:PostMessage(UM_PROGRESS);最后是在cmainframe的cpp文件中的函数关联和函数的实现ON_MESSAGE(UM_PROGRESS, OnProgress)!

LRESULT CMainFrame::OnProgress(WPARAM, LPARAM){CRect rect;m_wndStatusBar.GetItemRect(2, &rect);//获取状态栏上窗格的矩形大小        m_progress.Create(WS_CHILD | WS_VISIBLE, rect, &m_wndStatusBar, 123);      m_progress.SetPos(50);return 0;}

不过上面的实现有一个缺陷:就是当窗口发生变化的时候,而进度栏的位置不会随着窗口的变化而变化,所以还需要作以下的修改:

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);elsem_progress.MoveWindow(&rect);//移动窗口    m_progress.SetPos(50);// 不为绘图消息调用 CFrameWnd::OnPaint()}

注意:有了以上的代码之后就不再需要postmessage()这个函数传递消息了!

c.让进度栏前进:只需要在ontimer()函数中添加代码:

m_progress.StepIt();//让进度栏前进!

8.获取鼠标在文本框上面的坐标:

需要在view类中添加消息响应函数onmousemove():

void CID092View::OnMouseMove(UINT nFlags, CPoint point){// TODO: 在此添加消息处理程序代码和/或调用默认值        CString str;str.Format(TEXT("X = %d, Y = %d"), point.x, point.y);//以一定的格式输出//第一种方法      //((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowTextW(str);//在状态栏上面设置文本信息      //第二种方法     ((CMainFrame*)GetParent())->SetMessageText(str);      //第三种方法     ((CMainFrame*)GetParent())->GetMessageBar()->SetWindowTextW(str);      //第四种方法      GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowTextW(str);CView::OnMouseMove(nFlags, point);}

注意:需要将m_wndStatusBar定义为公有,要不就访问不了!

9.为程序设计一个启动画面:在vs2008中,没有像vc6.0中可以快速的添加组件就可以解决启动画面的组件,所以需要自己去设计一个类来实现,这可以参照我博客的文章,有提到如何去添加这个类的!