现在的位置: 首页 > 综合 > 正文

孙鑫MFC在vs2010下实现的笔记(第9课 定制外观)

2014年09月05日 ⁄ 综合 ⁄ 共 6978字 ⁄ 字号 评论关闭

9 定制外观<
xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

新建单文档的应用程序Style

1修改窗口大小,窗口名

CMainFrame::PreCreateWindow(CREATESTRUCT& cs)中对cs进行修改。

修改大小:

cs.cx=300;

       cs.cy=200;

更改窗口明称:

cs.style&=~FWS_ADDTOTITLE;   //或者cs.style= WS_OVERLAPPEDWINDOW;

       cs.lpszName ="fushenghao";

窗口创建后改变外观,在CMainFrame::OnCreate函数中修改

//SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW); //设置窗口类型

SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE)&~WS_MAXIMIZEBOX);              //获取窗口类型后去掉最大化按钮

 

2修改光标图标和背景

窗口的类型和大小是在创建窗口的时候设定的,而图标光标是在设计窗口类的时候指定的,由MFC底层代码自动生成的。

可以编写自己的窗口类然后注册,在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 =::DefWindowProcA;       //默认回调函数

       wndcls.lpszClassName ="fsh";

       wndcls.lpszMenuName =NULL;

       wndcls.style =CS_HREDRAW|CS_VREDRAW;

 

       RegisterClass(&wndcls);

       cs.lpszClass ="fsh";

 

发现这样只能改变图标,不能改变光标和背景,因为view覆盖在框架类之上,因此在view类的PreCreateWindow函数中设置:

cs.lpszClass ="fsh";

可以使用AfxRegisterWndClass函数

CMainFrame::PreCreateWindow中:

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

            LoadIcon(NULL,IDI_WARNING)); 

//第一个参数是窗口类型,第二个光标,第三个背景,第四个图标,图标改为感叹号,框架类中光标背景无意义设为0

CStyleView::PreCreateWindow中:

cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,

LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0);

   //光标设为十字,背景为黑色

窗口创建后修改图标光标背景

OnCreate()中修改:

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

 

修改光标图标可以在view类中增加WM_CREATE响应函数OnCreate函数,并添加如下代码:

SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));

 SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));

创建一个不断变化的图标。用定时器和SetClassLong完成

a.准备三个图标文件,放在RES文件夹,Insert->Resource-三个图标,

b.CMainFrame中增加图标句柄数组,m_hIcons[3]

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

//之前的图标都是系统图标所以第一个参数都设置为NULL,现在是自己的图标所以第一个参数要设置为应用程序句柄,使用了三种方法获取应用程序句柄。MAKEINTRESOURCE是一个宏,它将整数转化为Win32的资源类型,简单的说它是一个类型转换#define
MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i)))

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

//此处需要用到theAPP对象,故要在文件中声明extern
CStyleApp theApp;

m_hIcons[2]=LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));

然后将其初始化

  c.然后在定时器中实现

SetTimer(1,1000,NULL);

CMainFram中添加ONTimer函数

void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
// TODO:  在此添加消息处理程序代码和/或调用默认值
static int index = 0;///static 变量 在数据区的 不是在栈中的
SetClassLong(m_hWnd, GCL_HICON, (long)m_hicons[index]);
index = ++index % 3;



3.工具栏的编程

创建一个工具图标,作为快捷方式

在资源-Toolbar-IDR_MAINFRAME中绘制一个新的工具栏图标,并将ID号改为IDM_TEST,Menu-IDR_MAINFRAME中帮助菜单下添加一个TEST菜单项,其ID号也设置为IDM_TEST,并为其在框架类中创建消息响应函数,添加响应代码MessageBox("test");

这样运行后菜单中的TEST菜单项和工具栏中的项有相同的作用。

 

工具栏中添加分隔符以及删除工具栏中一个图标

添加分隔符只需在工具栏资源中将图标拖动一下即可,删除一个图标只需将该图标从工具栏资源中拖出即可。

4.创建一个新的工具栏的方法

第一步:

在资源中创建一个新的工具栏资源,ID号为IDR_TOOLBAR1

第二步:

MainFrm.h中增加protectedCToolBar类型的成员变量:CToolBar  m_newToolBar;

第三步:调用CreateExLoadToolBar函数

CMainFrame::OnCreate函数中添加如下代码:

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("未能创建工具栏");

              return -1;      // 未能创建

       }

       m_newToolBar.EnableDocking (CBRS_ALIGN_ANY); 

// 使工具栏可以停靠在客户端任意一个位置

//EnableDocking(CBRS_ALIGN_ANY);  //让主框架窗口可以支持任意位置停靠,由于之前调用过,所以这里不用再调用了

       DockControlBar(&m_newToolBar);    // 使工具栏可以停靠在主框架窗口上

点击“新的工具栏”菜单时,隐藏工具栏

第一种方法:

在菜单资源上增加一个菜单项“新的工具栏”,IDIDM_VIEW_NEWTOOL,并在框架程序中创建响应函数OnViewNewtool(),在该函数中:

if(m_newToolBar.IsWindowVisible())

       {

              m_newToolBar.ShowWindow(SW_HIDE);

       }

 else

    {

               m_newToolBar.ShowWindow(SW_SHOW);

        }

        RecalcLayout();  //工具栏隐藏后让工具条也消失

    DockControlBar(&m_newToolBar);    //让工具栏被拖动后,隐藏显示功能不出错

 

第二种方法:

OnViewNewtool()函数中添加如下代码:

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

//第二个参数为ture时显示工具栏,false时隐藏工具栏,第三个参数为false让显示的时候立即显示没有延时

给“新的工具栏”菜单项加复选标记

给该菜单项增加UPDATE COMMAND UI响应函数CMainFrame:: OnUpdateViewNewtool
(CCmdUI *pCmdUI)
,并添加代码:

pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());    //为真复选上,即在该菜单项前打钩

 

5.状态栏编程

第一步:

在字符串表资源中添加两个资源:

IDS_TIMER  时钟

IDS_PROGRESS   进度栏

第二步:

MainFrm.cpp文件中指示器数组indicators中添加这两个资源ID.

static UINT indicators[] =

{

       ID_SEPARATOR,           // 状态行指示器

       IDS_TIMER,               // 新添加的时间指示器

       IDS_PROGRESS,           // 新添加的进度栏指示器

       ID_INDICATOR_CAPS,

       ID_INDICATOR_NUM,

       ID_INDICATOR_SCRL,

};

 

第三步:

至此可以在窗口右下角显示五个状态条,时钟、进度栏、大小写等,为了让时钟栏显示时间在OnCreate函数中添加如下代码:

CTime t=CTime::GetCurrentTime();      //获取当前时间

       CString str=t.Format ("%H:%M:%S");     //以时:分:秒格式显示

 

       CClientDC dc(this);

       CSize sz=dc.GetTextExtent (str);         //获得str显示所需要的大小

 

       int index=0;

       index=m_wndStatusBar.CommandToIndex(IDS_TIMER);  //获得时钟栏在状态指示器数组中的位置,其实就是1.

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

//设置时钟栏的长度

       m_wndStatusBar.SetPaneText (index,str);   //将时间在状态栏显示

第四步:

设置一个定时器,在定时器响应函数中,重新获取当前时间,并显示,用以更新显示的时间。

6.进度栏

Mainfrm.h中增加protected的成员变量CProgressCtrl    m_progress

OnCreate中添加如下代码:

CRect rect;

m_wndStatusBar.GetItemRect(2,&rect);  //获取状态栏中第二项即进度栏的位置

m_progress.Create(WS_CHILD | WS_VISIBLE,// | PBS_VERTICAL,

       rect,&m_wndStatusBar,123);   //创建进度栏,第一个参数是属性,可以是水平的竖直的,第二个参数是位置,第三个参数是父窗口指针,这里设置为状态栏窗口,最后一个参数随便取的一个ID号。

    m_progress.SetPos(50);       //设置进度条中当前进度,100为满格,50为半格

这时运行发现不正确,矩形大小获取不正确,这是因为在OnCreate中状态栏还没有创建完成,因此,获取失败,解决办法可以是自定义消息,当程序执行OnCreate消息时,将自定义的消息放入消息队列中,当Oncreate消息执行完成后,再执行自定义的消息响应函数。

3MainFrm.h#define
UM_PROGRESS  WM_USER+1   //
自定义消息号要大于WM_USER

MainFrm.h中添加消息映射函数afx_msg LRESULT OnProgress(WPARAM
,LPARAM);

MainFrm.cpp中消息映射中添加ON_MESSAGE ( UM_PROGRESS, &CMainFrame::OnProgress
)

MainFrm.cpp中,消息响应函数:

LRESULT CMainFrame::OnProgress(WPARAM ,LPARAM)

{

 CRect rect;

 m_wndStatusBar.GetItemRect(2,&rect);

 m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH,

  rect,&m_wndStatusBar,123);

 m_progress.SetPos(50);

 return true;

}

4最后在OnCreate中调用 PostMessage(UM_PROGRESS);//不能用SendMessage()因为这个函数发送的消息是立即响应的,即Oncreate响应还没结束就去响应自定义的消息

解决重绘时进度栏改变的问题

OnPain()中重写代码

 CRect rect;

 m_wndStatusBar.GetItemRect(2,&rect);

 m_progress.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH,

  rect,&m_wndStatusBar,123);

 m_progress.SetPos(50);

此时将OnCreatePostMessage(UM_PROGRESS);注释掉,因为创建窗口的过程就调用了OnPain()函数。为了让进度随时间改变在定时器消息处理函数中加入

 m_progress.StepIt();

7.显示鼠标位置

View中增加OnMouseMove()处理函数

 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);

 // ((CMainFrame*)GetParent())->m_wndStatusBar.SetPaneText (0,str);

 GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);

以上五种方法人选一种

8.加入启动画面

  Project-Component and ->Visual C++ Components->SplashScreen->插入

vs2010下暂时还没有找到插入组件操作。

抱歉!评论已关闭.