《VC++深入详解》学习笔记 第九章 定制应用程序的外观

1.修改应用程序窗口的外观

 (1)在窗口创建之前修改:在CMainFrame类的PreCreateWindow成员函数中进行修改

 (2)在窗口创建之后修改:在CMainFrame类的Oncreate函数中使用SetWindowLong函数(第二个参数指定为GWL_STYLE

     Todo:获得窗口的现有类型用GetWindowLong函数

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

 (1)在窗口创建之前修改:

       1.CMainFrame类的PreCreateWindow成员函数中进行修改(编写自己的窗口类注册,菜单名可以设为NULLMFC模板自己提供了菜单)

     全局函数AfxGetInstanceHandle可以用来获取当前应用程序的实例句柄(所有以Afx开头的函数都是应用程序框架类函数,也就是全局函数,程序的所有类都可以调用)

     修改后程序图标改变但背景和光标没有改变,因为视类窗口覆盖在框架类窗口之上。修改背景和光标只能在视类的PreCreateWindow中修改

     2.用全局函数AfxRegisterWndClass,设定窗口的类型,光标,图标,背景

函数声明:LPCTSTR AFXAPI AfxRegisterWndClassUINT nClassStyle,HCURSOR hCursor = 0,HBRUSH hbrBackground = 0,HICON hIcon = 0;

//它的返回值就是注册后的类名,可以直接将这个返回值作为程序中随后创建窗口时所依赖的类

       CMainFrame类的PreCreateWindow函数中添加代码:

       cd.lpszClass = AfxRegisterWndClass(参数)

 这样窗口的图标就改变了,不需要再去整个重新定义一个窗口类,在视类中也可以调用这个函数来修改背景和光标

2)在窗口创建之后修改:利用全局API函数:SetClassLong,该函数用来重置指定的窗口所属窗口类的WNDCLASSEX结构体中指定数据成员的属性(CMainFrameOnCreate函数中修改图标,视类的OnCreate函数中修改背景和光标)

函数声明:DWORD SetClassLongHWND hWnd,int nIndex,LONG dwNewLong;

//nIndex指定要设置的属性的索引

//dwNewLong指定要设置的新属性的值

//eg:SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));

3.模拟动画图标(几幅图标,循环显示):利用定时器和SetClassLong函数实现

  (1)加载图标资源:添加资源,调用LoadIcon函数加载

     m_hIcons = LoadIcon(AfxGetInstanceHandle(),MAKINTRESOURCE(IDI_ICON1));

//使用系统图标,第一个参数为NULL,使用自定义图标第一个参数为当前实例句柄

//得到实例句柄的其他方法:theApp.m_hInstanceAfxGetApp->m_hInstance,

//其中,使用theApp要声明这个变量在外部定义的extern CStyleApp theApp

//第二个参数需要图标的名称,或者图标资源标识符的字符串,而我们只知道图标的ID

//需要通过MAKEINTRESOURCE宏将资源ID转化为相应的资源标识符字符串

 (2)定时器的处理

     1.CMainFrame类的OnCreate函数中添加代码:SetTimer11000NULL);

     2.CMainFrame类添加定时器消息(WM_TIMER)的响应函数,并在该函数中调用SetClassLong函数改变应用程序的图标

4.工具栏编程

 (1)资源编辑窗口中,双击工具栏图标就可以知道该图标的属性(工具栏图标的ID和菜单栏某一菜单项是相同的)

 (2)创建工具栏

    1.CToolBarCControlBarCWndCCmdTargetCObject,所以工具栏也是一个窗口

    2.方法一:(1)创建工具栏资源

             2)构造CToolBar对象

             3)调用CreateCreateEx函数创建Windows工具栏,并把它与已创建的CToolBar对象关联起来

             4)调用LoadToolBar函数加载工具栏资源

函数原型:BOOL CreateCWnd* pParentWnd,

DWORD dwStyle = WS_CHILD|WS_VISIBLE|CBRS_TOP,UINT nID = AFX_IDW_TOOLBAR;

// pParentWnd指向工具栏对象的父窗口

//指定工具栏的样式

//指定工具栏子窗口的ID

    3.方法二:(1)构造CToolBar对象

             2)调用CreateCreateEx函数创建Windows工具栏,并把它与已创建的CToolBar对象关联起来

             3)调用LoadBitmap函数加载包含工具栏按钮图像的位图

             4)调用SetButton函数设置按钮样式,并把工具栏上的一个按钮与位图中的一个图像关联

3MFC创建工具栏的过程

    1. CMainFrameOnCreate函数中:先调用CreateEx函数创建程序的工具栏对象,接着调用LoadToolBar函数加载工具栏资源,接着调用工具栏对象的EnableDocking成员函数设置工具栏停靠的位置,接着调用CMainFrame对象的EnableDocking成员函数设置主框架窗口的停靠,最后调用DockContrilBar函数,让工具栏停靠在主框架窗口上

4)创建自定义的工具栏

     1.按方法一创建

     2.工具栏的显示和隐藏:显示和隐藏用ShowWindow函数;用IsWindowVisible函数判断工具栏窗口当前是否可见

     3.窗口上的工具栏被隐藏或显示后,停靠在窗口的其他控制条对象的位置可能会有所变动,需要调用框架类的RecalcLayout成员函数来重新调整它们的位置

      函数原型:virtual void RecalcLayout(BOOL bNotifu = TRUE);

     4.工具栏拖动以后,隐藏后再显示,在拖动后的位置出现:CFrameWnd类的成员函数ShowControlBar,该函数的作用是隐藏或显示指定的控制条(不再用ShowWindow函数)

      函数原型:void ShowContrilBar(CContrilBar* pBar,BOOL bShow,BOOL bDelay);

// pBar指向将要显示或隐藏的控制条

// bShow  TRUE:显示;FALSE:隐藏

// bDelay  TRUE:延迟显示,FALSE:立即显示

5.状态栏编程

  1)状态栏分为两部分,左边是提示行,右边3个窗格,主要用来显示Caps LockNum LockScroll Lock键的状态,称为状态栏指示器

 (2)状态栏对象也在CMainFrame类中定义,与状态栏相关的MFC类是CStatusBar

     1MFCOnCreate函数中创建状态栏:先调用状态栏对象的Create函数创建状态栏对象,接着调用SetIndicators函数设置状态栏指示器,其中用了一个数组参数:indicators,这个数组是在CMainFrame类源文件的前部定义的,数组内容分别对应状态栏的提示行和Caps LockNum LockScroll Lock键的状态

     2.想要修改状态栏的外观,例如添加或减少状态栏上的窗格,则只需要在indicators数组中添加或减少想要的字符串资源ID即可

  3)在程序的状态栏上显示系统时间和一个进度条控件

     1.为程序增加两个新的字符串资源

     2.将这两个新的字符串资源ID添加到indicators数组中

     3.显示系统时间:CTIME类成员函数GetCurrentTime(得到系统时间);Format(得到一个包含格式化时间的字符串);为了将字符串显示到状态栏的窗格上,可以调用CStatusBar类的SetPaneText函数

      函数原型:BOOL SetPaneTextint nIndexLPCTSTR lpszNewText,BOOL bUpdate = TRUE;

//第一个参数是窗格在指示器数组中的索引,第二个参数是窗格上显示的文本,、、//第三个参数是BOOL类型,TRUE:设置窗格文本后,该窗格变成是无效的,当下//WM_PAINT消息发送后,该窗格将发生重绘,该参数默认值为TRUE

        CTime t = CTime::GetCurrentTime();

        CString str = t.Format(“%H:%M:%S”);

        m_wndStatusBar.SetPaneText(1,str);

       1)如果在设置窗格的文本时不知道窗格的索引,可以调用CStatusBar类的另一个成员函数;CommandToIndex,通过指定资源ID来得到相应的索引

       2)如果窗格太小不能显示完整时间,可以利用CStatusBar类的另一个成员函数:SetPaneInfo实现

        函数原型:void SetPaneInfo(int nIndex,UINT nID,UINT nStyle,int cwWidth);

//第一个参数指定将要设置其样式的窗格索引,第二个参数指定窗格重新设置的//ID,第三个参数指示窗格的样式,第四个参数指定窗格的新宽度

            获得字符串长度,要用CDC的成员函数GetTextExtent,所以先定义一个DC,如:CClientDC,然后调用GetTextExtent得到时间字符串显示的长度

    3)这个时间是静止的,如果让它动起来,要利用定时器,在WM_TIMER消息响应函数中重新获得当前时间并显示。

6.进度栏编程

 1 CProgressCtrlCwnd的子类,也是一个窗口类,要在程序中使用进度栏,首先需要构造一个CProgressCtrl对象,然后调用CProgressCtrl类的Create函数创建进度栏控件

    函数原型:BOOL CreateDWORD dwStyle,const RECT& rect,

CWnd* pParentWnd, UINT nID;

//第一个参数为进度栏控件的类型,第二个参数指定进度栏控件的大小和位置

//第三个参数指定进度栏的父窗口,第四个参数指定进度栏控件的ID

2)在窗口中创建进度栏

     1.CMainFrame类的头文件中定义一个CPregressCtrl类型的成员变量;

     2.CMainFrame类的OnCreate函数中在窗口创建完成后,创建进度栏控件,调用Create函数

     3.利用CProgressCtrl类的SetPos成员函数可以设置进度栏上的当前进度

     4.在状态栏的窗格中创建进度栏

       1)获得该窗格的区域:CStatusBar类的GetItemRect成员函数

 函数原型:void GetItemRect(int nIndex,LPRECT lpRect) const;

//第一个参数为窗格索引,第二个参数用来接受指定索引的窗格的矩形区域

          2)在该区域上显示进度条,将状态栏对象作为进度栏的父窗口

          CRect rect;     (在CMainFrameOnCreate函数中)

          m_wndStatusBar.GetItemRect(2,&rect);             m_progress.Create(WS_CHILD|WS_VISIBLE,rect,&m_wndStatusBar,123);

          m_progress.SetPos(50);

          3)此时得到的矩形无效,因为此时状态栏的初始化工作还没完成,只有OnCreate函数完成后,才能获得窗口状态栏上窗格的矩形区域。我们可以这样:自定义一个消息,然后在CMainFrame类的OnCreate函数中在其返回之前发送这条消息,最后在自定义消息的响应函数中获得状态栏上的窗格的矩形区域

             1.Windows中每条消息都用一个特定的整数值表示,WM_USER是系统提供的一个常量,小于这个常量的都是Windows系统保留的,我们自定义的消息要大于这个常(用户定义的消息一般要以UM_开头)

             在CMainFrame类的头文件定义自定义消息#define UM_PROGRESS WM_USER+1   

             2.CMainFrame类的头文件中,在两个AFC_MSG宏的外面添加自定义消息响应函数的声明(OnProgress),如果在发送该消息时,还需要附带发送一些数据,在声明这个函数时,就应该让其带有与消息相关的两个附加参数wParamlParam,否则,可以没有参数 afx_msg void OnProgress();

             3.CMainFrame类的源文件中,在消息映射表的两个注释宏之外添加UM_PROGRESS这一自定义消息的消息映射ON_MESSAGE(UM_PROGRESS,OnProgress)

             4.添加这个消息响应函数的实现

       CRect rect;    

       m_wndStatusBar.GetItemRect(2,&rect);

       m_progress.Create(WS_CHILD|WS_VISIBLE,rect,&m_wndStatusBar,123);

       m_progress.SetPos(50);

              5.CMainFrameOnCreate函数中利用SendMessage函数发送UM_PROGRESS这个自定义的消息  SendMessageUM_PROGRESS);

              6.使用SendMessage发送消息,不能达到我们的目的,因为这个函数发送消息的机制,它是直接把消息发送给消息响应函数,由消息响应函数处理完成后,SendMessage函数才返回。这里要用PostMessage函数,PostMessage函数把消息放到消息队列中,然后立即返回,之后程序使用GetMessage函数把消息取出,再逐条执行

              7.窗口尺寸发生变化时,进度栏显示的位置发生错误,这因为当程序尺寸发生变化时,窗口重绘,窗口的状态栏的尺寸也会随之变化,之前OnProgress代码中获得窗格区域就不正确了,我们需要为CMainFrame类添加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);//也可以用SetWindowPos函数

          }

         m_progress.SetPos(50);

//如果不进行判断,第二次调用该函数时,因为m_progress.Create重复创建进度//条并与m_progress关联,会出错

              8.让进度栏动起来:CProgress类的StepIt成员函数,该函数将使进度栏控件的当前位置按照一定的步长前进,而步长可以用SetStep来设置,对于进度栏来说,还可以设置它的范围,这可以通过SetRange函数实现

7.在状态栏上显示鼠标当前位置

 1)捕获鼠标移动消息(视类中完成)

 2)响应函数中添加代码

       CString str;

       Str.Format(“x=%d,y=%d”,point.x.point.y);

       ((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);

//这样就可以把鼠标当前位置显示在状态栏的第一个窗格中

3)不同的方法

    1.调用SetWindowText函数设置状态栏窗口的文本((2)所用的方法),因为上述代码用到了框架类的类型,所以要在视类包含头文件”MainFrm.h”

    2.利用CFrameWnd类的成员函数:SetMessageText实现,该函数的作用是在ID0值的状态栏窗格上设置一个字符串

     CMainFrameCFrameWnd的子类,继承了这个函数

        ((CMainFrame*)GetParent())->SetMessageTextstr;

    3.CFrameWnd类的成员函数:GetMessageBar返回状态栏对象的指针

 ((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);

    4.利用CWnd类的成员函数GetDescendantWindow获得程序状态栏对象的指针,这个函数的功能是通过指定的ID来获得子孙窗口,这个函数将搜索当前窗口的整个子窗口树,不仅仅搜索当前窗口的直接子窗口

函数原型:CWnd* GetDescendantWindow(int nID,BOOL bOnlyPerm = FALSE)const;  GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);

    TODO:对于一些常用的控制条,MFC都已经预先定义了ID

8.启动画面

 1VC++组件库中选择Splash screen组件,然后单击【insert】按钮

 2)在CMainFrame类的OnCreate函数中添加代码:

      CSplashWnd::showSplashScreen(this);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值