1 Tab Ctrl Tab
属性页控件可以在一个窗口中添加不同的页面,然后在页选择发生改变时得到通知。MFC中使用CTabCtrl类来封装属性页控件的各种操作。通过调用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,
dwStyle中可以使用以下一些属性页控件的专用风格: T
CS_BUTTONS 使用按钮来表示页选择位置
TCS_MULTILINE 分行显示页选择位置
TCS_SINGLELINE 只使用一行显示页选择位置
在控件创建后必需向其中添加页面才可以使用,添加页面的函数为:
BOOL InsertItem( int nItem, LPCTSTR lpszItem );
nItem为位置,从零开始,
lpszItem为页选择位置上显示的文字。如果你希望在页选择位置处显示一个图标,你可以调用
BOOL InsertItem( int nItem, LPCTSTR lpszItem, int nImage );
nImage指明所使用的图片位置。
(在此之前必须调用CImageList * SetImageList( CImageList * pImageList );设置正确的ImageList)
此外CTabCtrl还提供了一些函数用于得到/修改控件的状态。
int GetCurSel( )/int SetCurSel( int nItem );用于得到/设置当前被选中的页位置。
BOOL DeleteItem( int nItem )/BOOL DeleteAllItems( );用于删除指定/所有页面。
void RemoveImage( int nImage );用于删除某页选择位置上的图标。
属性页控件的消息映射同样使用ON_NOTIFY宏,形式如同:
ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXTab(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。
对于列表控件可能取值和对应的数据结构为:
TCN_SELCHANGE 在当前页改变后发送,所用结构:NMHDR TCN_SELCHANGING 在当前页改变时发送可以通过返回TRUE来禁止页面的改变,所用结构:NMHDR 一般来讲在当前页发生改变时需要隐藏当前的一些子窗口,并显示其它的子窗口。
下面的伪代码演示了如何使用属性页控件:
CParentWnd::OnCreate(...) { m_tab.Create(...);
m_tab.InsertItem(0,"Option 1");
m_tab.InsertItem(1,"Option 2");
Create a edit box as the m_tab's Child Create a static box as the m_tab's Child edit_box.ShowWindow(SW_SHOW); // edit box在属性页的第一页
static_box.ShowWindow(SW_HIDE); // static box在属性页的第二页 }
void CParentWnd::OnSelectChangeTab(NMHDR* pNMHDR, LRESULT* pResult)
{//处理页选择改变后的消息
if(m_tab.GetCurSel()==0) {//根据当前页显示/隐藏不同的子窗口
edit_box.ShowWindow(SW_SHOW); static_box.ShowWindow(SW_HIDE); }
else {// edit_box.ShowWindow(SW_HIDE); static_box.ShowWindow(SW_SHOW); } }
2. Tool Bar
工具条也是常用的控件。MFC中使用CToolBar类来封装工具条控件的各种操作。通过调用
BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR );创建一个窗口,dwStyle中可以使用以下一些工具条控件的专用风格:
CBRS_TOP 工具条在父窗口的顶部
TCBRS_BOTTOM 工具条在父窗口的底部
CBRS_FLOATING 工具条是浮动的 创建一个工具条的步骤如下:先使用Create创建窗口,然后使用BOOL LoadToolBar( LPCTSTR lpszResourceName );直接从资源中装入工具条,或者通过装入位图并指明每个按钮的ID,具体代码如下:
UINT uID[5]={IDM_1,IDM_2,IDM_3,IDM_4,IDM_5}; m_toolbar.Create(pParentWnd); m_toolbar.LoadBitmap(IDB_TOOLBAR); m_toolbar.SetSizes(CSize(20,20),CSize(16,16));//设置按钮大尺寸和按钮上位图的尺寸 m_toolbar.SetButtons(uID,5); AppWizard在生成代码时也会同时生成工具条的代码,同时还可以支持停靠功能。所以一般是不需要直接操作工具条对象。 工具条上的按钮被按下时发送给父窗口的消息和菜单消息相同,所以可以使用ON_COMMAND宏进行映射,同样工具条中的按钮也支持 ON_UPDATE_COMMAND_UI的相关操作,如SetCheck,Enable,你可以将按钮的当作菜单上的一个具有相同ID菜单项。
3. Status Bar
状态条用于显示一些提示字符。MFC中使用CStatusBar类来封装状态条控件的各种操作。通过调用 BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR );创建一个窗口,dwStyle中可以使用以下一些状态条控件的专用风格: CBRS_TOP 状态条在父窗口的顶部 TCBRS_BOTTOM 状态条在父窗口的底部 创建一个状态条的步骤如下:先使用Create创建窗口,然后调用BOOL SetIndicators( const UINT* lpIDArray, int nIDCount );设置状态条上各部分的ID,具体代码如下: UINT uID[2]={ID_SEPARATOR,ID_INDICATOR_CAPS}; m_stabar.Create(pParentWnd); m_stabar.SetIndicators(uID,2); 通过CString GetPaneText( int nIndex )/BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE )可以得到/设置状态条上显示的文字。 Tip:在创建状态条时最好将状态条中所有的部分ID(除MFC自定义的几个用于状态条的ID外)都设置为ID_SEPARATOR,在生成后调用 void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );改变其风格,ID和宽度。 AppWizard在生成代码时也会同时生成状态条的代码。所以一般是不需要直接创建状态条对象。此外状态条上会自动显示菜单上的命令提示(必须先在资源中定义),所以也不需要人为设置显示文字。 状态条支持ON_UPDATE_COMMAND_UI的相关操作,如SetText,Enable。
4.Dialog Bar Dialog Bar类似一个静态的附在框架窗口上的对话框,由于Dialog Bar可以使用资源编辑器进行编辑所以使用起来就很方便,在设计时就可以对Dialog Bar上的子窗口进行定位。用于显示一些提示字符。MFC中使用CDialogBar类来Dialog Bar控件的各种操作。通过调用 BOOL Create( CWnd* pParentWnd, UINT nIDTemplate, UINT nStyle, UINT nID );创建一个窗口,nIDTemplate为对话框资源,nID为该Dialog Bar对应的窗口ID,nStyle中可以使用以下一些状态条控件的专用风格: CBRS_TOP Dialog Bar在父窗口的顶部 TCBRS_BOTTOM Dialog Bar在父窗口的底部 CBRS_LEFT Dialog Bar在父窗口的左部 CBRS_RIGHT Dialog Bar在父窗口的右部 对于Dialog Bar的所产生消息需要在父窗口中进行映射和处理,例如Dialog Bar上的按钮,需要在父窗口中进行ON_BN_CLICKED或ON_COMMAND映射,Dialog Bar上的输入框可以在父窗口中进行ON_EN_CHANGE,ON_EN_MAXTEXT等输入框对应的映射。 Dialog Bar支持ON_UPDATE_COMMAND_UI的相关操作,如SetText,Enable。
5. 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar 运行时程序界面如界面图,该程序拥有一个工具条用于显示两个命令按钮,一个用于演示如何使按钮处于检查状态,另一个根据第一个按钮的状态来禁止/允许自身。(设置检查状态和允许状态都通过OnUpdateCommand实现)此外Dialog Bar上有一个输入框和按钮,这两个子窗口的禁止/允许同样是根据工具条上的按钮状态来确定,当按下Dialog Bar上的按钮时将显示输入框中的文字内容。状态条的第一部分用于显示各种提示,第二部分用于利用OnUpdateCommand显示当前时间。同时在程序中演示了如何设置菜单项的命令解释字符(将在状态条的第一部分显示)和如何设置工具条的提示字符(利用一个小的ToolTip窗口显示)。 生成应用:利用AppWizard生成一个MFC工程,图例,并设置为单文档界面图例,最后选择工具条,状态条和ReBar支持,图例 修改菜单:利用资源编辑器删除多余的菜单并添加一个新的弹出菜单和三个子菜单,图例,分别是: 名称 ID 说明字符 Check IDM_CHECK SetCheck Demo/nSetCheck Demo Disable IDM_DISABLE Disable Demo/nDisable Demo ShowText on DialogBar IDM_SHOW_TXT ShowText on DialogBar Demo/nShowText on DialogBar /n前的字符串将显示在状态条中作为命令解释,/n后的部分将作为具有相同ID的工具条按钮的提示显示在ToolTip窗口中。 修改 Dialog Bar:在Dialog Bar中添加一个输入框和按钮,按钮的ID为IDM_SHOW_TXT与一个菜单项具有相同的ID,这样可以利用映射菜单消息来处理按钮消息(当然使用不同ID值也可以利用ON_COMMAND来映射Dialog Bar上的按钮消息,但是ClassWizard没有提供为Dialog Bar上按钮进行映射的途径,只能手工添加消息映射代码)。图例 修改工具条:在工具条中添加两个按钮,ID值为IDM_CHECK和IDM_DISABLE和其中两个菜单项具有相同的ID值。图例 利用ClassWizard为三个菜单项添加消息映射和更新命令。图例 修改MainFrm.h文件 //添加一个成员变量来记录工具条上Check按钮的检查状态。
protected: BOOL m_fCheck; //手工添加状态条第二部分用于显示时间的更新命令,和用于禁止/允许输入框的更新命令 //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnCheck(); afx_msg void OnUpdateCheck(CCmdUI* pCmdUI); afx_msg void OnDisable(); afx_msg void OnUpdateDisable(CCmdUI* pCmdUI); afx_msg void OnShowTxt(); afx_msg void OnUpdateShowTxt(CCmdUI* pCmdUI); //}}AFX_MSG //上面的部分为ClassWizard自动产生的代码 afx_msg void OnUpdateTime(CCmdUI* pCmdUI); //显示时间 afx_msg void OnUpdateInput(CCmdUI* pCmdUI); //禁止/允许输入框 修改MainFrm.cpp文件 //修改状态条上各部分ID #define ID_TIME 0x705 //作为状态条上第二部分ID static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_SEPARATOR, //先设置为ID_SEPARATOR,在状态条创建后再进行修改 }; //修改消息映射 //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(IDM_CHECK, OnCheck) ON_UPDATE_COMMAND_UI(IDM_CHECK, OnUpdateCheck) ON_COMMAND(IDM_DISABLE, OnDisable) ON_UPDATE_COMMAND_UI(IDM_DISABLE, OnUpdateDisable) ON_COMMAND(IDM_SHOW_TXT, OnShowTxt) ON_UPDATE_COMMAND_UI(IDM_SHOW_TXT, OnUpdateShowTxt) //}}AFX_MSG_MAP //以上部分为ClassWizard自动生成代码 ON_UPDATE_COMMAND_UI(ID_TIME, OnUpdateTime) ////显示时间 ON_UPDATE_COMMAND_UI(IDC_INPUT_TEST, OnUpdateInput) //禁止/允许输入框 //修改OnCreate函数,重新设置状态条第二部分ID值 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { .... // by wenyy 修改状态条上第二部分信息 m_wndStatusBar.SetPaneInfo(1,ID_TIME,SBPS_NORMAL,60);//set the width return 0; } //修改经过映射的消息处理函数代码 void CMainFrame::OnCheck() { //在Check按钮被按下时改变并保存状态 m_fCheck=!m_fCheck; } void CMainFrame::OnUpdateCheck(CCmdUI* pCmdUI) { //Check按钮是否设置为检查状态 pCmdUI->SetCheck(m_fCheck); } void CMainFrame::OnDisable() { //Disable按钮被按下 AfxMessageBox("you press disable test"); } void CMainFrame::OnUpdateDisable(CCmdUI* pCmdUI) { //根据Check状态决定自身禁止/允许状态 pCmdUI->Enable(m_fCheck); } void CMainFrame::OnShowTxt() { //得到Dialog Bar上输入框中文字并显示 CEdit* pE=(CEdit*)m_wndDlgBar.GetDlgItem(IDC_INPUT_TEST); CString szO; pE->GetWindowText(szO); AfxMessageBox(szO); } void CMainFrame::OnUpdateShowTxt(CCmdUI* pCmdUI) { //Dialog Bar上按钮根据Check状态决定自身禁止/允许状态 pCmdUI->Enable(m_fCheck); } void CMainFrame::OnUpdateInput(CCmdUI* pCmdUI) { //Dialog Bar上输入框根据Check状态决定自身禁止/允许状态 pCmdUI->Enable(m_fCheck); } void CMainFrame::OnUpdateTime(CCmdUI* pCmdUI) { //根据当前时间设置状态条上第二部分文字 CTime timeCur=CTime::GetCurrentTime(); char szOut[20]; sprintf( szOut, "%02d:%02d:%02d", timeCur.GetHour(), timeCur.GetMinute(),timeCur.GetSecond()); pCmdUI->SetText(szOut); }
6. General Window 从VC提供的MFC类派生图中我们可以看出窗口的派生关系,派生图,所有的窗口类都是由CWnd派生。所有CWnd的成员函数在其派生类中都可以使用。本节介绍一些常用的功能给大家。 改变窗口状态: BOOL EnableWindow( BOOL bEnable = TRUE );可以设置窗口的禁止/允许状态。
BOOL IsWindowEnabled( );可以查询窗口的禁止/允许状态。 BOOL ModifyStyle( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 )/BOOL ModifyStyleEx( DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0 );可以修改窗口的风格,而不需要调用SetWindowLong BOOL IsWindowVisible( ) 可以检查窗口是否被显示。
BOOL ShowWindow( int nCmdShow );将改变窗口的显示状态,nCmdShow可取如下值:
SW_HIDE 隐藏窗口
SW_MINIMIZE SW_SHOWMAXIMIZED 最小化窗口
SW_RESTORE 恢复窗口
SW_SHOW 显示窗口
SW_SHOWMINIMIZED 最大化窗口
改变窗口位置: void MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );可以移动窗口。
void GetWindowRect( LPRECT lpRect ) ;可以得到窗口的矩形位置。
BOOL IsIconic( ) ;可以检测窗口是否已经缩为图标。
BOOL SetWindowPos( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );可以改变窗口的Z次序,此外还可以移动窗口位置。 使窗口失效,印发重绘: void Invalidate( BOOL bErase = TRUE );使整个窗口失效,bErase将决定窗口是否产生重绘。
void InvalidateRect( LPCRECT lpRect, BOOL bErase = TRUE )/void InvalidateRgn( CRgn* pRgn, BOOL bErase = TRUE );将使指定的矩形/多边形区域失效。 窗口查找: static CWnd* PASCAL FindWindow( LPCTSTR lpszClassName, LPCTSTR lpszWindowName );可以以窗口的类名和窗口名查找窗口。任一参数设置为NULL表对该参数代表的数据进行任意匹配。如FindWindow("MyWnd",NULL) 表明查找类名为MyWnd的所有窗口。
BOOL IsChild( const CWnd* pWnd ) 检测窗口是否为子窗口。 CWnd* GetParent( ) 得到父窗口指针。 CWnd* GetDlgItem( int nID ) 通过子窗口ID得到窗口指针。 int GetDlgCtrlID( ) 得到窗口ID值。 static CWnd* PASCAL WindowFromPoint( POINT point );将从屏幕上某点坐标得到包含该点的窗口指针。 static CWnd* PASCAL FromHandle( HWND hWnd );通过HWND构造一个CWnd*指针,但该指针在空闲时会被删除,所以不能保存供以后使用。 时钟: UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );可以创建一个时钟,如果lpfnTimer回调函数为NULL,窗口将会收到WM_TIMER消息,并可以在afx_msg void OnTimer( UINT nIDEvent );中安排处理代码 BOOL KillTimer( int nIDEvent );删除一个指定时钟。 可以利用重载来添加消息处理的虚函数: afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );窗口被创建时被调用 afx_msg void OnDestroy( );窗口被销毁时被调用 afx_msg void OnGetMinMaxInfo( MINMAXINFO FAR* lpMMI );需要得到窗口尺寸时被调用 afx_msg void OnSize( UINT nType, int cx, int cy );窗口改变大小后被调用 afx_msg void OnMove( int x, int y );窗口被移动后时被调用 afx_msg void OnPaint( );窗口需要重绘时时被调用,你可以填如绘图代码,对于视图类不需要重载OnPaint,所有绘图代码应该在OnDraw中进行 afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );接收到字符输入时被调用 afx_msg void OnKeyDown/OnKeyUp( UINT nChar, UINT nRepCnt, UINT nFlags );键盘上键被按下/放开时被调用 afx_msg void OnLButtonDown/OnRButtonDown( UINT nFlags, CPoint point );鼠标左/右键按下时被调用 afx_msg void OnLButtonUp/OnRButtonUp( UINT nFlags, CPoint point );鼠标左/右键放开时被调用 afx_msg void OnLButtonDblClk/OnRButtonDblClk( UINT nFlags, CPoint point );鼠标左/右键双击时被调用 afx_msg void OnMouseMove( UINT nFlags, CPoint point );鼠标在窗口上移动时被调用 7.关于WM_NOTIFY的使用方法 WM_NOTIF在WIN32中得到大量的应用,同时也是随着CommControl的出现 WM_NOTIFY成为了CommControl的基本消息。可以这样说CommControl的所有的新增特性都通过WM_NOTIFY来表达。同时 WM_NOTIFY也为CommControl的操作带来了一致性。
WM_NOTIFY消息中的参数如下: idCtrl = (int) wParam; pnmh = (LPNMHDR) lParam; 其中lParam为一个 typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR; 结构指针从消息的参数我们已经可以分辩出消息的来源,但是这些信息还不足以分辩出消息的具体含义。所以我们需要更多的数据来得到更多的信息。MS的做法是对每种不同用途的通知消息都定义另一种结构来表示,同时这中结构里包含了struct tagNMHDR,所以你只要进行一下类型转换就可以得到数据指针。例如对于LVN_COLUMNCLICK消息(用于在ListCtrl的列表头有鼠标点击是进行通知),结构为; typedef struct tagNMLISTVIEW{ NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; } NMLISTVIEW, FAR *LPNMLISTVIEW; 在这个结构的最开始也就包含了struct tagNMHDR,所以在不损失数据和产生错误的情况下向处理消息的进程提供了更多的信息。 此外通过WM_NOTIFY我们可以一种完全一样的方式进行消息映射,如同在前几章中所见到的一样。 使用如下形式:ON_NOTIFY( wNotifyCode, id, memberFxn )。 处理函数也有统一的原型:afx_msg void memberFxn( NMHDR * pNotifyStruct, LRESULT * result ); 在MFC消息映射的内部将根据定义消息映射时所使用的wNotifyCode和WM_NOTIFY中参数中pnmh->code(pnmh = (LPNMHDR) lParam)进行匹配,然后调用相应的处理函数。 还有一点是利用WM_NOTIFY/ON_NOTIFY_REFLECT可以在窗口内部处理一些消息,从而建立可重用的控件。