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

MFC 定制应用程序外观 — 总结

2018年02月07日 ⁄ 综合 ⁄ 共 4336字 ⁄ 字号 评论关闭

一、修改应用程序的外观

首先我们注意到,一个应用程序的窗口外观关联到两层含义:

1.用于创建窗口的窗口类样式。
2.创建窗口时的窗口样式。

所以,当我们想要修改一个应用程序的外观时,可以从这两方面任一个入手。

 

一、通过修改创建窗口时的窗口样式,来改变应用程序外观

1.在窗口创建前修改

在创建一个窗口时,CWnd类的派生类会调用PreCreateWindow函数来完成创建窗口前需要完成的操作。
我们先来看下这个函数的原型:

CWnd::PreCreateWindow
virtual BOOL PreCreateWindow( CREATESTRUCT& cs );    // 注意 cs  是个引用

其中CREATESTRUCT 中的各字段与CreateWindowEx 函数参数都是一一对应的。
所以,在这里我们应该认识到,这个结构保存着创建窗口时的具体样式同信息。
于是,我们可以通过修改这个结构的各个相应的字段,来修改创建窗口时的样式。

2.在创建窗口之后修改

在窗口创建之后,我们可以通过SetWindowLong函数来修改窗口的属性。

CWnd类的派生类在其OnCreate函数中完成其窗口的创建工作,我们可以在这个函数的return 语句之前来调用SetWindowLong。
下面是这个函数的原型:

LONG SetWindowLong( HWND hWnd, int nIndex, LONG dwNewLong);
当然,当我们想得到某一窗口的一个属性时,也好通过GetWindowLong函数来实现。

其函数原型:
LONG GetWindowLong( HWND hWnd, int nIndex);

 

二、通过修改创建窗口时的窗口类样式,来改变应用程序外观

1.在窗口创建前修改

首先我们应该认识到一点,在PreCreateWindow函数中的参数cs的lpszclass保存着用来创建窗口的窗口类名。
所以,如果我们想要修改创建窗口时的窗口类样式,应在PreCreateWindow函数中自定义我们的窗口类并注册之,
然后将其名赋给cs.lpszClass,之后在创建窗口时自会用我们定义的窗口类来建立窗口。

 

但是,有几点需要引起我们的注意:

  1. 我们的应用程序中有两个窗口:CMainFrame类的框架窗口 和 CXXXView 类的视图窗口。
  2. 两个窗口,也即说明可对应同一个窗口类,也可分别各自对应窗口类。
  3. 且视图窗口总是覆盖在框架窗口之上。所以,框架窗口的窗口类可不指定窗口光标样式同背景样式,而视图窗口可不指定图标样式。

可能这样操作下来很麻烦,所以MFC 为我们提供了AfxRegisterWndClass 来简化注册窗口类的操作,并返回窗口类的名字。

下面是这个函数的原型:

LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0,HBRUSH hbrBackground = 0, HICON hIcon = 0 );

操作方法如下:

cs.lpszClass = AfxRegisterWndClass(.....);

这样自会用我们自定义的窗口类来创建窗口。

 

2.在创建窗口之后修改

同窗口一样,在窗口类创建之后,我们可以通过SetClassLong函数来修改窗口类的属性。

下面是这个函数的原型:

DWORD SetClassLong( HWND hWnd, int nIndex, LONG dwNewLong);

 

二、工具栏编程

创建工具栏的方法:

1.创建工具栏资源。
2.在框架类CMainFrame中添加一个CToolBar 类对象,作为成员变量。
3.调用CToolBar类的CreateEx来创建一个工具栏。
4.调用CToolBar类的LoadToolBar来加载工具栏资源。
5.调用CToolBAr类的EnableDocking让工具栏可停靠在客户区的任意位置。
6.调用CMainFrame类的DockControlBar让这个新的工具栏停靠在主框架窗口上。

下面是需要用到的几个函数的原型:

BOOL CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle = TBSTYLE_FLAT, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect rcBorders = CRect(0, 0, 0, 0), UINT nID = AFX_IDW_TOOLBAR);

BOOL LoadToolBar( LPCTSTR lpszResourceName );
BOOL LoadToolBar( UINT nIDResource );

 

virtual void RecalcLayout( BOOL bNotify = TRUE );                                           // 用于完成控制条窗口的重新放置

void ShowControlBar( CControlBar* pBar, BOOLbShow, BOOL
bDelay );      // 用于控制工具栏的可见状态

 

 

 

 三、状态栏编程

状态栏概述:

状态分为两部分。

其中左边最长的那部分称为提示行,当我们把鼠标移动到某个菜单项或工具按钮上时,该部分将显示相应的提示信息。

而其右边的若干个空格,主要用来显示Caps Lock,,Num Lock和Scroll Lock 的状态,称为状态栏指示器。

一般我们的应用程序已经为我们创建了一个状态栏,但我们还是需要了解下创建状态栏的具体过程。

1.在主框架类CMainFrame中定义一个CStatusBar 类对象,作为成员变量。

  已提供:CStatusBar   m_wndStatusBar;

2.在主框架类CMainFrame的OnCreate函数中创建状态栏,并加载一些需要的信息。

已提供:

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

这里我们重点关注SetIndicators函数,其函数原型:

BOOL SetIndicators( const UINT* lpIDArray, int nIDCount );

此成员函数用来将每一个指示器的ID设置为由数组lpIDArray的相应元素指定的值,加载由每一个ID指定的字符串资源,并将这个字符串设置为此指示器的文本。

而indicators则是在CMainFrame类源文件中已定义的一个数组:
static UINT indicators[] =
{
    ID_SEPARATOR,           // 状态行指示器
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
};

 

为状态栏添加文本并显示:

如果想要在状态栏上添加一个字符串数据,可在indicators数组中添加元素。之后编译连接自可添加。

显示文本

  下面我们将演示一个实例:在状态栏上实时显示当前时间。

  1.   打开资源编辑器,在字符串列表中添加一个字符串 :IDS_TIMER   "时钟"
  2.   在CMainFrame类源文件的indicators数组中添加该字符串资源ID.
  3.    首先我们要获取当前时间

                 CTime    t   = CTime::GetCurrentTime();
                 CString  str = t.Format(TEXT("%H:%M:%S"))

      下面是实时显示时间:

  •    通过CStatusBar类的CommandToIndex函数,获取当前指示器在状态栏的索引。

                        int index = m_wndStatusBar.CommandToIndex(IDS_TIMER);

  •    设置该指示器完整显示所需的长度。可通过CStatusBar类的SetPaneInfo来设置。

                      CClientDc   dc(this);
                      CSize       sz = dc.GetTextExtent(str);
                      m_wndStatusBar.SetPaneInfo(index, IDS_TIMER, SBPS_NORMAL, sz.cx);

  •      更新指示器的文本显示:

                      m_WndStatusBar.SetPaneText(index, str);

 当然,为了实时更新时间的显示,这段代码应放置在定时器中。

 

 四、进度栏编程

 创建进度栏的步骤:

1.在主框架类CMainFrame中定义一个CProgressCtrl 类对象,作为其成员变量。

2.调用CProgressCtrl类的成员函数Create来创建进度栏。该函数原型如下:

CProgressCtrl::Create
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

 

注意两个函数:

CProgressCtrl::SetPos
int SetPos( int nPos );    // 设置进度条当前进度

CProgressCtrl::SetStep
int SetStep( int nStep );  // 设置进度条增长步长,默认为10

 

CProgressCtrl::StepIt
int StepIt( );                    // 使进度条按设置的步长增长

 

分享一个实例: 在状态栏中显示进度条

在主框架类CMainFrame类的OnPaint函数中,添加如下代码:

 CRect rect;
 m_wndStatusBar.GetItemRect(2, &rect);
 if (!m_progress.m_hWnd)
  m_progress.Create(WS_CHILD | WS_VISIBLE, rect, &m_wndStatusBar, 123);    
 else
  m_progress.MoveWindow(rect);

而为了实现进度条的步长增长,可以定时器中添加如下代码:

m_progress.StepIt();

 

 

CProgressCtrl::SetStep
int SetStep( int nStep );
CProgressCtrl::SetStep
int SetStep( int nStep );

 

 

 

 

 

 

 

抱歉!评论已关闭.