定制应用程序外观

本节主要学习了

1.      修改MFC AppWizard向导生成的框架程序外观和大小,这既可以在窗口创建之前,也可以在窗口创建之后进行。

2.      修改程序窗口的图标,光标,背景的方法。在创建窗口之前,通过设计窗口类来修改程序窗口的图标,光标,背景;在窗口创建之后,通过SetClassLong函数修改窗口的图标,光标和背景。

3.      实现一个动态变化的图标的例子。

4.      工具栏和状态栏编程。

5.      程序启动画面的创建。

 

BOOLCMainFrame::PreCreateWindow(CREATESTRUCT& cs)//这是一个虚函数

{

       if(!CFrameWnd::PreCreateWindow(cs) )

              returnFALSE;

       //TODO: Modify the Window class or styles here by modifying

       //  the CREATESTRUCT cs

       //1.在窗口创建之前修改窗口的默认外观。

   /*cs.cx = 300;

       cs.cy= 200;

       cs.style&= ~FWS_ADDTOTITLE;  //改变将文档标题添加到窗口标题上。可以让窗口显示自己设置的标题。

       //cs.style= cs.style & ~ FWS_ADDTOTITLE;

       //cs.style= WS_OVERLAPPEDWINDOW;

       //cs.style= WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE; //该成员的初始定义代码。

       cs.lpszName= "xiaobai";*/

 

       //2.修改窗口的光标,图标,背景

   //通过编写自己的窗口类并注册,然后让随后的窗口按照自己编写的窗口类去创建。

 

       /*WNDCLASSwndclass;

       wndclass.cbClsExtra= 0;

       wndclass.cbWndExtra= 0;

       wndclass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);

       wndclass.hCursor= LoadCursor(NULL,IDC_HELP);

       wndclass.hIcon= LoadIcon(NULL,IDI_ERROR);

       wndclass.hInstance= AfxGetInstanceHandle();  //获取当前应用程序的实例句柄。Afx开头的函数都是应用程序框架类函数,也就是全局函数。

       wndclass.lpfnWndProc= ::DefWindowProc;

       wndclass.lpszClassName= "xiaobai";

       wndclass.lpszMenuName= NULL;

       wndclass.style= CS_HREDRAW | CS_VREDRAW;//这里并不是窗口的类型,而是窗口类的类型。指定窗口类具有水平重绘和垂直重绘这两种类型。

 

       RegisterClass(&wndclass);

       cs.lpszClass= "xiaobai"; */

 

       //cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));

       cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,0);

       //用来设定窗口的类型,光标,背景,图标。返回值是注册之后的类名。

       returnTRUE;

}

 

       //SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);

   SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE) &~WS_MAXIMIZEBOX);//取消最大化

       //GWL就是GetWindowLong的缩写。GWL_STYLE指定获取窗口的类型。

 

BOOLCStyleView::PreCreateWindow(CREATESTRUCT& cs)

{

       //TODO: Modify the Window class or styles here by modifying

       //  the CREATESTRUCT cs

   //cs.lpszClass = "xiaobai"; //思考一下为什在CMainFram中注册的窗口类,在这里还可以用。

       //在MFC程序中,如果要修改应用程序窗口的图标,则应在框架类中进行,因为在框架窗口中才有标题栏,所以才能修改位于该标题栏上的图标

       //如果想要修改应用程序的背景和光标,就应该在视类中进行。

 

       //cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW |CS_VREDRAW,LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0);

       cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,0);//只给第一个参数赋值,其余参数都为0,会发现

       //背景是透明的,图标光标都是默认的。

       returnCView::PreCreateWindow(cs);

}

 

       ON_MESSAGE(UM_PROGRESS,OnProgress)      //对于自定义消息来说,使用的是ON_MESSAGE宏实现这一功能。

END_MESSAGE_MAP()

 

static UINT indicators[] =    //标识提示行和状态栏指示器的ID数组

{

       ID_SEPARATOR,// status line indicator 提示行

       IDS_TIMER,

       IDS_PROGRESS,

       ID_INDICATOR_CAPS,      //分别是Caps Lock,Num Lock,Scroll Lock键的状态指示器。

       ID_INDICATOR_NUM,

       ID_INDICATOR_SCRL,

};

 

extern CStyleApp theApp;  //声明这个变量是在外部的一个源文件中定义的

 

int CMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)

{

       if(CFrameWnd::OnCreate(lpCreateStruct) == -1)

              return-1;

      

       if(!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

              |CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

              !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))     //MFC自动创建的工具栏和主菜单的资源ID是一样的,也就是说,在MFC编程中,一个ID可以表示多种资源。

       {

              TRACE0("Failedto create toolbar\n");

              return-1;      // fail to create

       }

 

       if(!m_wndStatusBar.Create(this) ||

              !m_wndStatusBar.SetIndicators(indicators,

                sizeof(indicators)/sizeof(UINT)))

       {

              TRACE0("Failedto create status bar\n");

              return-1;      // fail to create

       }

 

       //TODO: Delete these three lines if you don't want the toolbar to

       //  be dockable

       m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);  //设置工具栏停靠的位置

       EnableDocking(CBRS_ALIGN_ANY);//上面的那个EnableDocking函数式工具栏对象的成员函数,目的是让工具栏对象可以停靠,而这里调用的是CFrameWnd对象的EnableDocking

                                     //成员函数,目的是让主框架窗口可以被停靠。

       DockControlBar(&m_wndToolBar);//让工具栏停靠在主框架窗口上。

 

       //在窗口创建之后修改窗口的样式

       SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));

 

       //模拟动画图标(3中加载自定义图标的方式)

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

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

       m_hIcons[2]= LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));//AfxGetApp可以获得当前应用程序对象的指针

 

       SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons[0]);

 

       SetTimer(1,1000,NULL);

 

       //创建自定义工具栏

       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))     //MFC自动创建的工具栏和主菜单的资源ID是一样的,也就是说,在MFC编程中,一个ID可以表示多种资源。

       {

              TRACE0("Failedto create toolbar\n");

              return-1;      // fail to create

       }

       m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);

       DockControlBar(&m_newToolBar);

 

       //在窗口中创建进度栏(思考一下在框架类中创建的进度栏怎嘛可以在视类窗口中显示)

       //m_progress.Create(WS_CHILD| WS_VISIBLE | PBS_SMOOTH,CRect(100,100,200,120),this,123);   //创建水平的进度栏

       //m_progress.SetPos(50);  //设置进度栏上当前位置

 

       //m_progress.Create(WS_CHILD| WS_VISIBLE | PBS_VERTICAL,CRect(100,100,120,200),this,321);  ///创建垂直的进度栏

       //m_progress.SetPos(40);

 

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

       /*CRectrect;

       m_wndStatusBar.GetItemRect(2,&rect);

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

       m_progress.SetPos(50);*/    //这种方式并不能让进度条在窗格中显示。只有在窗口创建完,即OnCreate函数执行完

                                   //才能获得窗口状态栏上窗格的矩形区域。

 

       //SendMessage(UM_PROGRESS);  //发送消息在OnCreate函数没有执行完,就去执行UM_PROGRESS消息的响应函数,

                                        //消息响应函数返回又回到OnCreate函数中执行到函数结束,这和上面的那段代码其实

                                       //是一样的效果

       m_wndStatusBar.SetPaneInfo(2,IDS_PROGRESS,SBPS_NORMAL,100);//设置窗格的宽度

       //PostMessage(UM_PROGRESS);//投递消息,把消息投递到消息队列中,程序通过GetMessage函数按顺序把消息一条一条的取出来

       //对于本程序,等程序执行完WM_CREATE消息后,才去执行UM_PROGRESS消息

 

   myCtrl.Create(WS_CHILD |WS_VISIBLE | PBS_SMOOTH,CRect(100,100,200,120),this,123);

       intnLower,nUpper;

       myCtrl.GetRange(nLower,nUpper);

       myCtrl.SetStep((nUpper-nLower)/4);

       myCtrl.StepIt();

       //CG: The following line was added by the Splash Screen component.

       CSplashWnd::ShowSplashScreen(this);

       return0;

}

 

void CMainFrame::OnTimer(UINT nIDEvent)

{

       staticint index = 0;  //作为一个静态的局部变量,他将存放在程序的数据区中,而不是在栈中分配空间。

       SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons[index]);

       index= ++index%3;  //小技巧:如果希望把某个数值始终限制在一个范围内,那么最好的办法就是进行取模运算(%)

 

       //在时钟状态栏指示器中显示时间

       CTimet = CTime::GetCurrentTime();

       CStringstr = t.Format("%H:%M:%S");

       CClientDCdc(this);

       CSizesz=dc.GetTextExtent(str);  //获得字符串的宽度和高度

 

       //intindex = 0;     //在不知道窗格的索引时,可以利用这个函数,根据窗格的ID来得到相应的索引。

       //index= m_wndStatusBar.CommandToIndex(IDS_TIMER);

   m_wndStatusBar.SetPaneInfo(1,IDS_TIMER,SBPS_NORMAL,sz.cx);

       m_wndStatusBar.SetPaneText(1,str);

 

       intnLower,nUpper;

       m_progress.GetRange(nLower,nUpper);

       m_progress.SetStep((nUpper-nLower)/10);  //设置每次前进的步长

       m_progress.StepIt();  //让进度栏的当前位置按照一定的步长前进

 

       CFrameWnd::OnTimer(nIDEvent);

}

 

//工具栏的显示或隐藏

void CMainFrame::OnViewNewtoolbar()

{

       //TODO: Add your command handler code here

       /*if(m_newToolBar.IsWindowVisible())   //判断工具栏是显示还是隐藏了

       {

              m_newToolBar.ShowWindow(SW_HIDE);

       }

       else

       {

              m_newToolBar.ShowWindow(SW_SHOW);

       }

       RecalcLayout();

/*当标准工具栏或状态栏隐藏或者显示,或者窗口调整大小时,调用这个方法。

方法原型为:virtualvoid RecalcLayout( BOOL bNotify = TRUE ); 

Parameters:   bNotify

Determines whether the active in-place itemfor the frame window receives notification of the layout change. If TRUE, theitem is notified; otherwise FALSE.

决定是否将焦点项目传递这个变化,如果是TRUE就通知子项目,否则,不传递。

这里m_wndToolBar1是自己定义的一个工具栏,:OnViewToolbar1()是一个菜单项的消息响应函数。

当工具栏显示时,点击这个菜单项,工具栏隐藏,然后调用RecalcLayout这个方法,重新布置窗口。

当工具栏隐藏式,点击这个菜单项,工具栏显示,然后调用RecalcLayout这个方法,重新布置窗口。

       DockControlBar(&m_newToolBar);*/

 

       ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);

       //显示或隐藏一个控件条 

       //pBar指向要显示或隐含的控件条   

       //bShow如果为TRUE ,指定控件条将显示;如果为FALSE,则隐藏。   

       //bDelay如果为TRUE,延迟显示控件条;如果为FALSE,则立即显示

}

 

//显示或隐藏工具栏时,取消或显示相应的菜单上的复选标记

void CMainFrame::OnUpdateViewNewtoolbar(CCmdUI*pCmdUI)

{

       pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());

       //通过为菜单项添加UPDATE_COMMAND_UI消息的响应,可以非常方便地为该菜单项设置或取消复选标记。

}

 

//这种方法在窗口发生重绘时,进度条的显示就会错位,要在窗口重绘的消息响应函数中添加下面的代码

void CMainFrame::OnProgress()

{

       CRectrect;

       m_wndStatusBar.GetItemRect(2,&rect);

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

       m_progress.SetPos(50);

}

 

void CMainFrame::OnPaint()

{

       CPaintDCdc(this); // device context for painting

      

       CRectrect;

       m_wndStatusBar.GetItemRect(2,&rect);

       if(!m_progress.m_hWnd)  //根据m_progress对象的窗口句柄是否为空判断进度栏是否被创建

       {

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

       }

       else

       {

              m_progress.MoveWindow(rect);//用SetWindowPos函数设置进度栏的位置比较麻烦,但功能比较多,例如它可以将程序窗口设置为顶层窗口

       }

       m_progress.SetPos(50);

       //Do not call CFrameWnd::OnPaint() for painting messages

}

发布了41 篇原创文章 · 获赞 5 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章