孙鑫vc++ 第九课 笔记 修改MFC AppWizard向导生成的框架程序的外观和大小


1、在窗口建立之前改变窗口外观,第三课讲mfc运行机制的时候说过这个函数了,留了一个后门给我们
   BOOL CMainFrame::PreCreateWindow(GREATESTRUCT& cs)
   {
      if(!CFrameWnd::PreCreateWindow(cs))
         return FALSE;
      改变cs结构体

      return TRUE;
   }
  
   改宽高,可以直接cs.x=*,cs.y=*
   改窗口标题,必须先改窗口的类型,因为原来默认FWS_ADDTOTITLE | WS_OVERLAPPEDWINDOW
      FWS_ADDTOTITLE 默认使用文档标题,去掉这个标志就可以了
       //cs.style&=~FWS_ADDTOTITLE;
       cs.style=WS_OVERLAPPEDWINDOW;
       cs.lpszName="http://www.sunxin.org";

1、在窗口建立之后改变窗口外观,在OnCreate()用SetWindowLong()
   LONG SetWindowLong(HWND hWnd,int nIndex,LONG dwNewLong);  //sdk函数,改变指定窗口的属性
                  要改变的窗口的句柄 你要改变的属性 新的值
   改变属性用GWL_STYLE指定改变的是窗口类型
  
   获取窗口信息
   LONG SetWindowLong(HWND hWnd,int nIndex); //哪个窗口,什么类型
  
   //SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);
   SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE) & ~WS_MAXIMIZEBOX);

2、改变图标,光标,背景,应该在PreCreateWindow()中编写
  
   获取当前应用程序的句柄
   HINSTANCE AfxGetInstanceHandle();

   通过重写窗口类,达到修改程序外观的目的
    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;   //cwnd类中有一个同名的函数,所以要用::区分
 wndcls.lpszClassName="sunxin.org";    //窗口类名
 wndcls.lpszMenuName=NULL;
 wndcls.style=CS_HREDRAW | CS_VREDRAW;

 RegisterClass(&wndcls); //注册窗口类
 cs.lpszClass="sunxin.org";  //把新的窗口类送给PreCreateWindow()中传入的参数cs

   修改窗口图标,应该在MainFrame类中修改,因为图标是属于框架类的
   修改光标,背景应该在View类中修改,因为那是view类窗口上的,把最后一句移到view同函数中即可

3、上面的方法太麻烦了,用另一个函数,
   LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,HCURSOR hCursor=0,HBRUSH hbrBackground=0,HICON hIcon=0);//窗口类型,光标,画刷,图标,返回新类的类名
   缺省参数,箭头光标,空画刷,windows标志图标

   可以这样写,达到上面一样的目的
   cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));
  
4、窗口建立后改变外观
   DWORD SetClassLong(HWND hWnd,int nIndex,LONG dwNewLong);  //改变WNDCLASSEX结构体的内容
                      哪个窗口   改变类型    新类型
   改变图标,可以用GCL_HICON,改变背景可以用GCL_HBRBACKCROUND

   SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));
              
   把资源id号改变为LPCTSTR的一个宏
   LPCTSTR MAKEINTRESOURCE(WORD wInteger);

   m_hIcons[0]=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));

   CTestApp的父类CWinApp有一个数据成员m_hInstance表示的当前的程序实例

   m_hIcons[1]=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));

   一个类内需要调用另一个类的成员对象,需要用extern声明
   extern CStyleApp theApp;  //声明在外部源文件当中定义的
   则,theApp.m_hInstance和AfxGetInstanceHandle()的效果是一样的

   m_hIcons[1]=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));

   CWinApp* AfxGetApp();  //返回一个CWinApp的指针
   m_hIcons[2]=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));
  
   让一个值在某一个范围内变化,可以用取模的方法
   index=++intdex%3

5、工具栏
   工具图标的id设成和某菜单项的一样,然后对菜单项命令消息编程就行了
   把工具栏图标往右拖动一点距离,就能产生分隔符了
   删除工具栏按钮,拖出工具栏就行了,用del键只能删除其上图象

  
6、创建工具栏
   CToolBar : CControlBar : CWnd : CCmdTarget : CObject
  
   第一种方法:
   1 建立工具栏资源
   2 创建CToolBar对象
   3 用Create()或者CreateEx()建立一个工具栏并与工具栏对象相关联
   4 用LoadToolBAr() 载入工具栏

   CToolBar::Create
   BOOL Create(CWnd* pParentWnd,DWORD dwStyle=WS_CHILD | WS_VISIBLE | CBRS_TOP,UINT nID=AFX_IDW_TOOLBAR);  //父窗口指针,工具栏样式,工具栏id

   CToolBar::CreateEx
   BOOL CreateEx(CWnd* pParentWnd,DWORD dwCtrlStyle=TBSTYLE_FLAT,DWORD dwStyle=WS_CHILD|WS_VISIBLE|CBRS_ALIGH_TOP,CRect rcBorders+CRect(0,0,0,0),UINT nID=AFX_IDW_TOOLBAR);  //父窗口指针,扩展风格,工具栏样式,工具栏宽度,工具栏id


   第二种方法:
   1 创建一个CToolBar对象
   2 调用Create()或者CreateEx()建立一个工具栏并与工具栏对象相关联
   3 调用LoadBitmap()载入工具栏图象
   4 调用SetButtons()设置工具栏样式并与图标关联

   让工具栏可以停靠
   CControlBar::EnableDocking
   void EnableDocking(DWORD dwStyle);
      CBRS_ALIGN_TOP 顶部
      CBRS_ALIGN_BOTTON 底部
  
   让框架窗口可以被停靠
   CFrameWnd::EnableDocking
   void EnableDocking(DWORD dwDockStyle); //MainFrame从CFrameWnd继承,所以此函数可以被直接调用
      CBRS_ALIGN_TOP 顶部
      CBRS_ALIGN_BOTTON 底部

   让工具栏停靠在主窗口下
   DockControlBar(CToolBar* hhh);

        if (!m_wndStatusBar.Create(this) ||
  !m_wndStatusBar.SetIndicators(indicators,
    sizeof(indicators)/sizeof(UINT)))
 {
  TRACE0("Failed to create status bar/n");
  return -1;      // fail to create
 }

 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
 EnableDocking(CBRS_ALIGN_ANY);
 DockControlBar(&m_wndToolBar);


7、判断一个窗口是否是可视的
   判断工具栏是否可视:m_newToolBar.IsWindowVisible(); //可视返回真,否则返回假
   如果工具栏处在停靠状态,调用IsWindowVisible()只会让工具栏上的按钮消失,工具栏还在
   调用下面的函数可以解决该问题
  
   CFrameWnd::RecalcLayout
   virtual void RecalcLayout(BOOL bNotify=TRUE);  //重新调整工具栏位置
   当工具栏处于浮动状态,调用以上2个函数后,只是按钮消失了,工具栏还在
   要解决该问题,还必须调用DockControlBar(&m_wndToolBar);

   这时,工具栏隐藏没问题,但恢复时会使工具栏出现在顶端,而不是在原来的位置浮动显示 

 
   第一种显示方法示例
   void CMainFrame::OnViewNewtool()
   {
 if(m_newToolBar.IsWindowVisible())
 {
  m_newToolBar.ShowWindow(SW_HIDE);
 }
 else
 {
  m_newToolBar.ShowWindow(SW_SHOW);
 }
 RecalcLayout();
 DockControlBar(&m_newToolBar);
   }

8、第二种显示方法
   CFrameWnd::ShowControlBar
   void ShowControlBar(CControlBar* pBar,BOOL bShow,Bool bDelay);
                       工具栏指针         真显假隐   显示延时否,真延时,假立即显示

   一个函数完成以上功能
   ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);

9、为菜单项加上复选标记
   添加菜单项UPDATE_COMMAND_UI响应消息及函数
   void CMainFrame::OnUpdateViewNewtool(CCmdUI* pCmdUI)
   {
       pCmdUI->SetCheck(m_newToolBar.IsWindowvisible());  //用SetCheck()设置
   }


10、状态栏
  
   CMainFrame.h中
   CStatusBar m_wndStatusBar;

   CMainFrame.cpp中
   static UINT indicators[] =   //内容的个数就是状态栏里的项目数
   {
 ID_SEPARATOR,           // status line indicator
 ID_INDICATOR_CAPS,      //在资源里的string tool定义
 ID_INDICATOR_NUM,
 ID_INDICATOR_SCRL,
   };

   if (!m_wndStatusBar.Create(this) ||
    !m_wndStatusBar.SetIndicators(indicators,  //这个就是上面定义的全局静态数组
        sizeof(indicators)/sizeof(UINT)))
   {
        TRACE0("Failed to create status bar/n");
        return -1;      // fail to create
   }

   如果想要在状态栏中添加自己的项目,资源里的string table定义自己的常量

11、在状态栏中添加时钟

    获取当前时间
    CTime::GetCurrentTime
    static CTime PASCAL GetCurrentTime();  //返回一个CTime对象,他表示了当前的时间
   
    格式化时间对象
    CTime::Format
    CString Format(LPCTSTR pFormat)const;   //格式化一个时间对象,返回为指定格式的字符串
    CString Format(UINT nFormatID)const;
        %D 天,%H 小时,%M 分钟,%S 秒,%%

    把信息输出到状态栏
    CStatusBar::SetPaneText
    BOOL SetPaneText(int nIndex,LPCTSTR lpszNewText,BOOL bUpdate=TRUE);
                     状态栏哪个格的索引  要输出的内容   wm_paint时重绘

    如果不知道你要输出的小格的索引,可以用下面的函数
    CStatusBar::CommandToIndex
    int CommandToIndex(UINT nIDFind)const; //通过资源字符串(就是那个静态数组)的id获取其索引

    改变小格的大小,以适应输出的内容,默认小格是很小的
    CStatusBar::SetPaneInfo
    void SetPaneInfo(int nIndex,UINT nID,UINT nStyle,int cxWidth);
                     小格索引   重新分配新的id  类型   小格宽度

    如何获取我们要显示的内容的宽度以赋值给cxWidth呢,用GetTextExtent();啊,前面说过了
 
   
 SetTimer(1,1000,NULL);

 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);
 m_wndStatusBar.SetPaneInfo(index,IDS_TIMER,SBPS_NORMAL,sz.cx);
 m_wndStatusBar.SetPaneText(index,str);

12、进度栏
    CProgressCtrl::CProgressCtrl
    CProgressCtrl();  //构造对象后用create()创建
  
    CProgressCtrl::Create
    BOOL Create(DWORD dwStyle,constRECT& rect,CWnd* pParentWnd,UINT nID);
                  类型          大小             父窗口         进度栏id号
    类型有:PBS_VERTICAL 垂直(默认是水平的)  PBS_SMOOTH 平滑

    设置进度栏进到哪个位置
    CProgressCtrl::SetPos
      SetPos(这个参数填个整数,50代表50%,也就是一半,当百分比用了)

    如何把进度条放到状态栏的小格当中呢
    首先要获得小格的矩形区域
    CStatusBar::GetItemRect
    void GetItemRect(int nIndex,LPRECT lpRect)const; //小格索引,用来接收矩形区域坐标的参数

 

    1 CProgressCtrl m_progress;
    2
/* CRect rect;
 m_wndStatusBar.GetItemRect(2,&rect);
 //m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_VERTICAL,
 // CRect(100,100,120,200),this,123);
 m_progress.Create(WS_CHILD | WS_VISIBLE,// | PBS_VERTICAL,
  rect,&m_wndStatusBar,123);
 m_progress.SetPos(50);*/
// SendMessage(UM_PROGRESS);
// PostMessage(UM_PROGRESS);
 // CG: The following line was added by the Splash Screen component.

 CSplashWnd::ShowSplashScreen(this);

13、自定义消息
    1 在头文件中#define UM_PROGRESS WM_USER+1
      消息都是一个整数值表示的
    2 写上消息宏 afx_msg void OnProgress();
    3 消息映射 ON_MESSAGE(UM_PROGESS,OnProgress)
    4 写响应函数
      void CMainFrame::OnProgress()
      {
 CRect rect;
 m_wndStatusBar.GetItemRect(2,&rect);
 m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
  rect,&m_wndStatusBar,123);
 m_progress.SetPos(50);
      }
    5 在使用的地方发送消息 SendMessage(UM_PROGRESS);或者PostMessage(UM_PROGRESS);两者是有差别的,
      SendMessage(UM_PROGRESS); //发送消息后直接到消息响应函数运行,结束后回到原函数直接运行
      PostMessage(UM_PROGRESS); //将消息添加到消息对列当中后立即回到调用函数,系统GetMessage()到该消息后才执行消息响应函数,这样就能够让原函数执行完毕后再操作

   在实例中,必须要让oncreate()执行完成,将窗口建立完毕后才能获取状态栏信息,所以用SendMessage(UM_PROGRESS);不合适,应该用PostMessage(UM_PROGRESS);

    void CMainFrame::OnPaint()
    {
 CPaintDC dc(this); // device context for painting
 
 // TODO: Add your message handler code here
 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);
 // Do not call CFrameWnd::OnPaint() for painting messages
    }

14、让进度栏前进
    设置进度栏前进步长
    CProgressCtrl::SetStep
    int SetStep(int nStep);

    进度栏前进
    StepIt();

    设置进度栏前进范围
    CProgressCtrl::SetRange
    void SetRange(short nLower,short nUpper);
    void SetRange32(int nLower,int nUpper); //默认0,100

    m_progress.StepIt();

15、状态栏左条显示文本
    直接用框架类的成员变量,但要把成员变量改成共有的,同时包含CMainFrame头文件
    ((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
   
    用框架类的成员函数
    CFrameWnd::SetMessageText
    void SetMessageText(LPCTSTR lpszText); //直接在状态栏放置文本,不需要框架类对象了

    ((CMainFrame*)GetParent())->SetMessageText(str);

    用GetMessageBar()
    CFrameWnd::GetMessageBar
    virtual CWnd* GetMessageBar(); //返回一个指向状态栏的指针

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

    用GetDescendantWindow()
    CWnd::GetDescendantWindow
    CWnd* GetDescendantWindow(int nID,BOOL bOnlyPerm=FALSE) const; //搜索所有子窗口直到找到给定id的窗口,并返回该窗口的指针  窗口id,是否返回临时窗口,true返回持久窗口,false可以返回临时窗口

    状态栏的id是多少呢?
    CStatusBar::Create
    BOOL Create(CWnd* pParentWnd,DWORD dwStyle=WS_CHILD|WS_VISIBLE|CBRS_BOTTOM,UINT nID=AFX_IDW_STATUS_BAR); //-------->最后这个就是系统给定的状态栏的id号
    系统为每个常用的工具窗口都预设了一个id号,可以通过一个已知的id用查找定义的方法找到定义的地方,或到mfc/include/找到定义文件

    GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);
    //这里不用(CMainFrame*)强制转换窗口类型,要不要转换,要看你后面所用的函数是属于哪个类的,属于CMainFrame,就转换为CMainFrame,属于CWnd就转换为CWnd, 但这里用的是CWnd::GetParent(),所以明显不用转换了

    void CStyleView::OnMouseMove(UINT nFlags, CPoint point)
    {

 CString str;
 str.Format("x=%d,y=%d",point.x,point.y);
 //((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
 //((CMainFrame*)GetParent())->SetMessageText(str);
 //((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);
 GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);
 CView::OnMouseMove(nFlags, point);
    }

16、启动画面
    1 工程-增加到工程-组件控件-选择splash screen-ok
      这样就已经有了一个启动画面了,他增加的是一个位图IDB_SPLASH和一个类CSplashWnd
      另外在框架类OnCreate()中添加了一句 CSplashWnd::ShowSplashScreen(this);
    2 延长显示时间
      在定时器中改变时间间隔 SetTimer(1,750,NULL); // 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值