一、修改应用程序的外观
首先我们注意到,一个应用程序的窗口外观关联到两层含义:
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,之后在创建窗口时自会用我们定义的窗口类来建立窗口。
但是,有几点需要引起我们的注意:
可能这样操作下来很麻烦,所以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数组中添加元素。之后编译连接自可添加。
显示文本
下面我们将演示一个实例:在状态栏上实时显示当前时间。
CTime t = CTime::GetCurrentTime();
CString str = t.Format(TEXT("%H:%M:%S"))
下面是实时显示时间:
int index = m_wndStatusBar.CommandToIndex(IDS_TIMER);
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 );