4.2 Static Box
静态文本控件的功能比较简单,可作为显示字符串,图标,位图用。创建一个窗口可以使用成员函数:
BOOL CStatic::Create( LPCTSTR lpszText, DWord dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对静态控件指明专门的风格。
SS_CENTER,SS_LEFT,SS_RIGHT 指明字符显示的对齐方式。
SS_GRAYRECT 显示一个灰色的矩形
SS_NOPREFIX 假如指明该风格,对于字符&将直接显示,否则&将作为转义符,&将不显示而在其后的字符将有下划线,假如需要直接显示&必须使用&&表示。
SS_BITMAP 显示位图
SS_ICON 显示图标
SS_CENTERIMAGE 图象居中显示
控制显示的文本利用成员函数SetWindowText/GetWindowText用于设置/得到当前显示的文本。
控制显示的图标利用成员函数SetIcon/GetIcon用于设置/得到当前显示的图标。
控制显示的位图利用成员函数SetBitmap/GetBitmap用于设置/得到当前显示的位图。下面一段代码演示如何创建一个显示位图的静态窗口并设置位图CStatic* pstaDis=new CStatic;
pstaDis->Create("",WS_CHILDWS_VISIBLESS_BITMAPSSCENTERIMAGE,
CRect(0,0,40,40),pWnd,1);
CBitmap bmpLoad;
bmpLoad.LoadBitmap(IDB_TEST);
pstaDis->SetBitmap(bmpLoad.Detach());
4.2 Static Box
静态文本控件的功能比较简单,可作为显示字符串,图标,位图用。创建一个窗口可以使用成员函数:
BOOL CStatic::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对静态控件指明专门的风格。
SS_CENTER,SS_LEFT,SS_RIGHT 指明字符显示的对齐方式。
SS_GRAYRECT 显示一个灰色的矩形
SS_NOPREFIX 假如指明该风格,对于字符&将直接显示,否则&将作为转义符,&将不显示而在其后的字符将有下划线,假如需要直接显示&必须使用&&表示。
SS_BITMAP 显示位图
SS_ICON 显示图标
SS_CENTERIMAGE 图象居中显示
控制显示的文本利用成员函数SetWindowText/GetWindowText用于设置/得到当前显示的文本。
控制显示的图标利用成员函数SetIcon/GetIcon用于设置/得到当前显示的图标。
控制显示的位图利用成员函数SetBitmap/GetBitmap用于设置/得到当前显示的位图。下面一段代码演示如何创建一个显示位图的静态窗口并设置位图CStatic* pstaDis=new CStatic;
pstaDis->Create("",WS_CHILDWS_VISIBLESS_BITMAPSSCENTERIMAGE,
CRect(0,0,40,40),pWnd,1);
CBitmap bmpLoad;
bmpLoad.LoadBitmap(IDB_TEST);
pstaDis->SetBitmap(bmpLoad.Detach());
4.3 Edit Box
Edit窗口是用来接收用户输入最常用的一个控件。创建一个输入窗口可以使用成员函数:
BOOL CEdit::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对输入控件指明专门的风格。
ES_AUTOHSCROLL,ES_AUTOVSCROLL 指明输入文字超出显示范围时自动滚动。
ES_CENTER,ES_LEFT,ES_RIGHT 指定对齐方式
ES_MULTILINE 是否答应多行输入
ES_PASSWORD 是否为密码输入框,假如指明该风格则输入的文字显示为*
ES_READONLY 是否为只读
ES_UPPERCASE,ES_LOWERCASE 显示大写/小写字符
控制显示的文本利用成员函数SetWindowText/GetWindowText用于设置/得到当前显示的文本。
通过GetLimitText/SetLimitText可以得到/设置在输入框中输入的字符数量。
由于在输入时用户可能选择某一段文本,所以通过void CEdit::GetSel( int& nStartChar, int& nEndChar )得到用户选择的字符范围,通过调用void CEdit::SetSel( int nStartChar, int nEndChar, BOOL bNoScroll = FALSE )可以设置当前选择的文本范围,假如指定nStartChar=0 nEndChar=-1则表示选中所有的文本。void ReplaceSel( LPCTSTR lpszNewText, BOOL bCanUndo = FALSE )可以将选中的文本替换为指定的文字。
此外输入框还有一些和剪贴板有关的功能,void Clear( );删除选中的文本,void Copy( );可将选中的文本送入剪贴板,void Paste( );将剪贴板中内容插入到当前输入框中光标位置,void Cut( );相当于Copy和Clear结合使用。
最后介绍一下输入框几种常用的消息映射宏:
ON_EN_CHANGE 输入框中文字更新后产生
ON_EN_ERRSPACE 输入框无法分配内存时产生
ON_EN_KILLFOCUS / ON_EN_SETFOCUS 在输入框失去/得到输入焦点时产生
使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。假如在对话框中使用输入框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
4.4 Scroll Bar
Scroll Bar一般不会单独使用,因为SpinCtrl可以取代滚动条的一部分作用,但是假如你需要自己生成派生窗口,滚动条还是会派上一些用场。创建一个滚动条可以使用成员函数: :
BOOL CEdit::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对滚动条指明专门的风格。
SBS_VERT 风格将创建一个垂直的滚动条。
SBS_HORZ 风格将创建一个水平的滚动条。
在创建滚动条后需要调用void SetScrollRange( int nMinPos, int nMaXPos, BOOL bRedraw = TRUE )设置滚动范围,
int GetScrollPos( )/int SetScrollPos( )用来得到和设置当前滚动条的位置。
void ShowScrollBar( BOOL bShow = TRUE );用来显示/隐藏滚动条。
BOOL EnableScrollBar( UINT nArrowFlags = ESB_ENABLE_BOTH )用来设置滚动条上箭头是否为答应状态。nArrowFlags可取以下值:
ESB_ENABLE_BOTH 两个箭头都为答应状态
ESB_DISABLE_LTUP 上/左箭头为禁止状态
ESB_DISABLE_RTDN 下/右箭头为禁止状态
ESB_DISABLE_BOTH 两个箭头都为禁止状态
假如需要在滚动条位置被改变时得到通知,需要在父窗口中定义对消息WM_VSCROLL/WM_HSCROLL的映射。方法为在父窗口类中重载
afx_msg void OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )/afx_msg void OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
所使用的消息映射宏为:ON_WM_VSCROLL( ),ON_WM_HSCROLL( ),在映射宏中不需要指明滚动条的ID,因为所有滚动条的滚动消息都由同样的函数处理。在OnHScroll/OnVScroll的第三个参数会指明当前滚动条的指针。第一个参数表示滚动条上发生的动作,可取以下值:
SB_TOP/SB_BOTTOM 已滚动到顶/底部
SB_LINEUP/SB_LINEDOWN 向上/下滚动一行
SB_PAGEDOWN/SB_PAGEUP 向上/下滚动一页
SB_THUMBPOSITION/SB_THUMBTRACK 滚动条拖动到某一位置,参数nPos指明当前位置(参数nPos在其它的情况下是无效的)
SB_ENDSCROLL 滚动条拖动完成(用户松开鼠标)
4.5 List Box/Check List Box
ListBox窗口用来列出一系列的文本,每条文本占一行。创建一个列表窗口可以使用成员函数:
BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对列表控件指明专门的风格。
LBS_MULTIPLESEL 指明列表框可以同时选择多行
LBS_EXTENDEDSEL 可以通过按下Shift/Ctrl键选择多行
LBS_SORT 所有的行按照字母顺序进行排序
在列表框生成后需要向其中加入或是删除行,可以利用:
int AddString( LPCTSTR lpszItem )添加行,
int DeleteString( UINT nIndex )删除指定行,
int InsertString( int nIndex, LPCTSTR lpszItem )将行插入到指定位置。
void ResetContent( )可以删除列表框中所有行。
通过调用int GetCount( )得到当前列表框中行的数量。
假如需要得到/设置当前被选中的行,可以调用int GetCurSel( )/int SetCurSel(int iIndex)。假如你指明了选择多行的风格,你就需要先调用int GetSelCount( )得到被选中的行的数量,然后int GetSelItems( int nMaxItems, LPINT rgIndex )得到所有选中的行,参数rgIndex为存放被选中行的数组。通过调用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框内指定行的字符串。
此外通过调用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在当前所有行中查找指定的字符传的位置,nStartAfter指明从那一行开始进行查找。
int SelectString( int nStartAfter, LPCTSTR lpszItem )可以选中包含指定字符串的行。
在MFC 4.2版本中添加了CCheckListBox类,该类是由CListBox派生并拥有CListBox的所有功能,不同的是可以在每行前加上一个检查框。必须注重的是在创建时必须指明LBS_OWNERDRAWFIXED或LBS_OWNERDRAWVARIABLE风格。
通过void SetCheckStyle( UINT nStyle )/UINT GetCheckStyle( )可以设置/得到检查框的风格,关于检查框风格可以参考4.1 Button中介绍。通过void SetCheck( int nIndex, int nCheck )/int GetCheck( int nIndex )可以设置和得到某行的检查状态,关于检查框状态可以参考4.1 Button中介绍。
最后介绍一下列表框几种常用的消息映射宏:
ON_LBN_DBLCLK 鼠标双击
ON_EN_ERRSPACE 输入框无法分配内存时产生
ON_EN_KILLFOCUS / ON_EN_SETFOCUS 在输入框失去/得到输入焦点时产生
ON_LBN_SELCHANGE 选择的行发生改变
使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。假如在对话框中使用列表框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
4.6 Combo Box/Combo Box Ex
组合窗口是由一个输入框和一个列表框组成。创建一个组合窗口可以使用成员函数:
BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对列表控件指明专门的风格。
CBS_DROPDOWN 下拉式组合框
CBS_DROPDOWNLIST 下拉式组合框,但是输入框内不能进行输入
CBS_SIMPLE 输入框和列表框同时被显示
LBS_SORT 所有的行按照字母顺序进行排序
由于组合框内包含了列表框,所以列表框的功能都能够使用,如可以利用:
int AddString( LPCTSTR lpszItem )添加行,
int DeleteString( UINT nIndex )删除指定行,
int InsertString( int nIndex, LPCTSTR lpszItem )将行插入到指定位置。
void ResetContent( )可以删除列表框中所有行。
通过调用int GetCount( )得到当前列表框中行的数量。
假如需要得到/设置当前被选中的行的位置,可以调用int GetCurSel( )/int SetCurSel(int iIndex)。通过调用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框内指定行的字符串。
此外通过调用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在当前所有行中查找指定的字符传的位置,nStartAfter指明从那一行开始进行查找。
int SelectString( int nStartAfter, LPCTSTR lpszItem )可以选中包含指定字符串的行。
此外输入框的功能都能够使用,如可以利用:
DWORD GetEditSel( ) /BOOL SetEditSel( int nStartChar, int nEndChar )得到或设置输入框中被选中的字符位置。
BOOL LimitText( int nMaxChars )设置输入框中可输入的最大字符数。
输入框的剪贴板功能Copy,Clear,Cut,Paste动可以使用。
最后介绍一下列表框几种常用的消息映射宏:
ON_CBN_DBLCLK 鼠标双击
ON_CBN_DROPDOWN 列表框被弹出
ON_CBN_KILLFOCUS / ON_CBN_SETFOCUS 在输入框失去/得到输入焦点时产生
ON_CBN_SELCHANGE 列表框中选择的行发生改变
ON_CBN_EDITUPDATE 输入框中内容被更新
使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。假如在对话框中使用组合框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
4.7 Tree Ctrl
树形控件TreeCtrl和下节要讲的列表控件 ListCtrl在系统中大量被使用,例如Windows资源治理器就是一个典型的例子。
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有答应有一个或多个或没有子结点。MFC中使用CTreeCtrl类来封装树形控件的各种操作。通过调用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些树形控件的专用风格:
TVS_HASLINES 在父/子结点之间绘制连线
TVS_LINESATROOT 在根/子结点之间绘制连线
TVS_HASBUTTONS 在每一个结点前添加一个按钮,用于表示当前结点是否已被展开
TVS_EDITLABELS 结点的显示字符可以被编辑
TVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点
TVS_DISABLEDRAGDROP 不答应Drag/Drop
TVS_NOTOOLTIPS 不使用ToolTip显示结点的显示字符
在树形控件中每一个结点都有一个句柄(HTREEITEM),同时添加结点时必须提供的参数是该结点的父结点句柄,(其中根Root结点只有一个,既不可以添加也不可以删除)利用
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );可以添加一个结点,pszItem为显示的字符,hParent代表父结点的句柄,当前添加的结点会排在hInsertAfter表示的结点的后面,返回值为当前创建的结点的句柄。下面的代码会建立一个如下形式的树形结构: +--- Parent1
+--- Child1_1
+--- Child1_2
+--- Child1_3
+--- Parent2
+--- Parent3
/*假设m_tree为一个CTreeCtrl对象,而且该窗口已经创建*/
HTREEITEM hItem,hSubItem;
hItem = m_tree.InsertItem("Parent1",TVI_ROOT);
在根结点上添加Parent1
hSubItem = m_tree.InsertItem("Child1_1",hItem);
//在Parent1上添加一个子结点
hSubItem = m_tree.InsertItem("Child1_2",hItem,hSubItem);
//在Parent1上添加一个子结点,排在Child1_1后面
hSubItem = m_tree.InsertItem("Child1_3",hItem,hSubItem);
hItem = m_tree.InsertItem("Parent2",TVI_ROOT,hItem);
hItem = m_tree.InsertItem("Parent3",TVI_ROOT,hItem);
假如你希望在每个结点前添加一个小图标,就必需先调用CImageList* SetImageList( CImageList * pImageList, int nImageListType );指明当前所使用的ImageList,nImageListType为TVSIL_NORMAL。在调用完成后控件中使用图片以设置的ImageList中图片为准。然后调用
HTREEITEM InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent = TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);添加结点,nImage为结点没被选中时所使用图片序号,nSelectedImage为结点被选中时所使用图片序号。下面的代码演示了ImageList的设置。 /*m_list 为CImageList对象
IDB_TREE 为16*(16*4)的位图,每个图片为16*16共4个图标*/
m_list.Create(IDB_TREE,16,4,RGB(0,0,0));
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
m_tree.InsertItem("Parent1",0,1);
//添加,选中时显示图标1,未选中时显示图标0
此外CTreeCtrl还提供了一些函数用于得到/修改控件的状态。
HTREEITEM GetSelectedItem( );将返回当前选中的结点的句柄。BOOL SelectItem( HTREEITEM hItem );将选中指明结点。
BOOL GetItemImage( HTREEITEM hItem, int& nImage, int& nSelectedImage ) / BOOL SetItemImage( HTREEITEM hItem, int nImage, int nSelectedImage )用于得到/修改某结点所使用图标索引。
CString GetItemText( HTREEITEM hItem ) /BOOL SetItemText( HTREEITEM hItem, LPCTSTR lpszItem );用于得到/修改某一结点的显示字符。
BOOL DeleteItem( HTREEITEM hItem );用于删除某一结点,BOOL DeleteAllItems( );将删除所有结点。
此外假如想遍历树可以使用下面的函数:
HTREEITEM GetRootItem( );得到根结点。
HTREEITEM GetChildItem( HTREEITEM hItem );得到子结点。
HTREEITEM GetPrevSiblingItem/GetNextSiblingItem( HTREEITEM hItem );得到指明结点的上/下一个兄弟结点。
HTREEITEM GetParentItem( HTREEITEM hItem );得到父结点。
树形控件的消息映射使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXTree(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于树形控件可能取值和对应的数据结构为:
TVN_SELCHANGED 在所选中的结点发生改变后发送,所用结构:NMTREEVIEW
TVN_ITEMEXPANDED 在某结点被展开后发送,所用结构:NMTREEVIEW
TVN_BEGINLABELEDIT 在开始编辑结点字符时发送,所用结构:NMTVDISPINFO
TVN_ENDLABELEDIT 在结束编辑结点字符时发送,所用结构:NMTVDISPINFO
TVN_GETDISPINFO 在需要得到某结点信息时发送,(如得到结点的显示字符)所用结构:NMTVDISPINFO
关于ON_NOTIFY有很多内容,将在以后的内容中进行具体讲解。
关于动态提供结点所显示的字符:首先你在添加结点时需要指明lpszItem参数为:LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为LPNMTVDISPINFO,然后填充其中item.pszText。但是我们通过什么来知道该结点所对应的信息呢,我的做法是在添加结点后设置其lParam参数,然后在提供信息时利用该参数来查找所对应的信息。下面的代码说明了这种方法: char szOut[8][3]={"No.1","No.2","No.3"};
//添加结点
HTREEITEM hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem, 0 );
hItem = m_tree.InsertItem(LPSTR_TEXTCALLBACK,...)
m_tree.SetItemData(hItem, 1 );
//处理消息
void CParentWnd::OnGetDispInfoTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
pTVDI->item.pszText=szOut[pTVDI->item.lParam];
//通过lParam得到需要显示的字符在数组中的位置
*pResult = 0;
}
关于编辑结点的显示字符:首先需要设置树形控件的TVS_EDITLABELS风格,在开始编辑时该控件将会发送TVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送TVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为LPNMTVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。假如编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息: //处理消息 TVN_BEGINLABELEDIT
void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
if(pTVDI->item.lParam==0);//判定是否取消该操作
*pResult = 1;
else
*pResult = 0;
}
//处理消息 TVN_BEGINLABELEDIT
void CParentWnd::OnBeginEditTree(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDI = (TV_DISPINFO*)pNMHDR;
if(pTVDI->item.pszText==NULL);//判定是否已经取消取消编辑
m_tree.SetItemText(pTVDI->item.hItem,pTVDI->pszText);
//重置显示字符
*pResult = 0;
}
上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。
4.8 List Ctrl
列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值。MFC中使用CListCtrl类来封装列表控件的各种操作。通过调用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些列表控件的专用风格:
LVS_ICON LVS_SMALLICON LVS_LIST LVS_REPORT 这四种风格决定控件的外观,同时只可以选择其中一种,分别对应:大图标显示,小图标显示,列表显示,具体报表显示
LVS_EDITLABELS 结点的显示字符可以被编辑,对于报表风格来讲可编辑的只为第一列。
LVS_SHOWSELALWAYS 在失去焦点时也显示当前选中的结点
LVS_SINGLESEL 同时只能选中列表中一项
首先你需要设置列表控件所使用的ImageList,假如你使用大图标显示风格,你就需要以如下形式调用:
CImageList* SetImageList( CImageList* pImageList, LVSIL_NORMAL);
假如使用其它三种风格显示而不想显示图标你可以不进行任何设置,否则需要以如下形式调用:
CImageList* SetImageList( CImageList* pImageList, LVSIL_SMALL);
通过调用int InsertItem( int nItem, LPCTSTR lpszItem );可以在列表控件中nItem指明位置插入一项,lpszItem为显示字符。除LVS_REPORT风格外其他三种风格都只需要直接调用InsertItem就可以了,但假如使用报表风格就必须先设置列表控件中的列信息。
通过调用int InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat , int nWidth, int nSubItem);可以插入列。iCol为列的位置,从零开始,lpszColumnHeading为显示的列名,nFormat为显示对齐方式,nWidth为显示宽度,nSubItem为分配给该列的列索引。
在有多列的列表控件中就需要为每一项指明其在每一列中的显示字符,通过调用
BOOL SetItemText( int nItem, int nSubItem, LPTSTR lpszText );可以设置每列的显示字符。nItem为设置的项的位置,nSubItem为列位置,lpszText为显示字符。下面的代码演示了如何设置多列并插入数据: m_list.SetImageList(&m_listSmall,LVSIL_SMALL);//设置ImageList
m_list.InsertColumn(0,"Col 1",LVCFMT_LEFT,300,0);//设置列
m_list.InsertColumn(1,"Col 2",LVCFMT_LEFT,300,1);
m_list.InsertColumn(2,"Col 3",LVCFMT_LEFT,300,2);
m_list.InsertItem(0,"Item 1_1");//插入行
m_list.SetItemText(0,1,"Item 1_2");//设置该行的不同列的显示字符
m_list.SetItemText(0,2,"Item 1_3");
此外CListCtrl还提供了一些函数用于得到/修改控件的状态。
COLORREF GetTextColor( )/BOOL SetTextColor( COLORREF cr );用于得到/设置显示的字符颜色。
COLORREF GetTextBkColor( )/BOOL SetTextBkColor( COLORREF cr );用于得到/设置显示的背景颜色。
void SetItemCount( int iCount );用于得到添加进列表中项的数量。
BOOL DeleteItem(int nItem);用于删除某一项,BOOL DeleteAllItems( );将删除所有项。
BOOL SetBkImage(HBITMAP hbm, BOOL fTile , int xOffsetPercent, int yOffsetPercent);用于设置背景位图。
CString GetItemText( int nItem, int nSubItem );用于得到某项的显示字符。
列表控件的消息映射同样使用ON_NOTIFY宏,形式如同:ON_NOTIFY( wNotifyCode, id, memberFxn ),wNotifyCode为通知代码,id为产生该消息的窗口ID,memberFxn为处理函数,函数的原型如同void OnXXXList(NMHDR* pNMHDR, LRESULT* pResult),其中pNMHDR为一数据结构,在具体使用时需要转换成其他类型的结构。对于列表控件可能取值和对应的数据结构为:
LVN_BEGINLABELEDIT 在开始某项编辑字符时发送,所用结构:NMLVDISPINFO
LVN_ENDLABELEDIT 在结束某项编辑字符时发送,所用结构:NMLVDISPINFO
LVN_GETDISPINFO 在需要得到某项信息时发送,(如得到某项的显示字符)所用结构:NMLVDISPINFO
关于ON_NOTIFY有很多内容,将在以后的内容中进行具体讲解。
关于动态提供结点所显示的字符:首先你在项时需要指明lpszItem参数为:LPSTR_TEXTCALLBACK。在控件显示该结点时会通过发送TVN_GETDISPINFO来取得所需要的字符,在处理该消息时先将参数pNMHDR转换为LPNMLVDISPINFO,然后填充其中item.pszText。通过item中的iItem,iSubItem可以知道当前显示的为那一项。下面的代码演示了这种方法: char szOut[8][3]={"No.1","No.2","No.3"};
//添加结点
m_list.InsertItem(LPSTR_TEXTCALLBACK,...)
m_list.InsertItem(LPSTR_TEXTCALLBACK,...)
//处理消息
void CParentWnd::OnGetDispInfoList(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR;
pLVDI->item.pszText=szOut[pTVDI->item.iItem];
//通过iItem得到需要显示的字符在数组中的位置
*pResult = 0;
}
关于编辑某项的显示字符:(在报表风格中只对第一列有效)首先需要设置列表控件的LVS_EDITLABELS风格,在开始编辑时该控件将会发送LVN_BEGINLABELEDIT,你可以通过在处理函数中返回TRUE来取消接下来的编辑,在编辑完成后会发送LVN_ENDLABELEDIT,在处理该消息时需要将参数pNMHDR转换为LPNMLVDISPINFO,然后通过其中的item.pszText得到编辑后的字符,并重置显示字符。假如编辑在中途中取消该变量为NULL。下面的代码说明如何处理这些消息: //处理消息 LVN_BEGINLABELEDIT
void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR;
if(pLVDI->item.iItem==0);//判定是否取消该操作
*pResult = 1;
else
*pResult = 0;
}
//处理消息 LVN_BEGINLABELEDIT
void CParentWnd::OnBeginEditList(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pLVDI = (LV_DISPINFO*)pNMHDR;
if(pLVDI->item.pszText==NULL);//判定是否已经取消取消编辑
m_list.SetItemText(pLVDI->item.iItem,0,pLVDI->pszText);
//重置显示字符
*pResult = 0;
}
上面讲述的方法所进行的消息映射必须在父窗口中进行(同样WM_NOTIFY的所有消息都需要在父窗口中处理)。
如何得到当前选中项位置:在列表控件中没有一个类似于ListBox中GetCurSel()的函数,但是可以通过调用GetNextItem( -1, LVNI_ALL LVNI_SELECTED);得到选中项位置。
4.9 Tab Ctrl
Tab属性页控件可以在一个窗口中添加不同的页面,然后在页选择发生改变时得到通知。MFC中使用CTabCtrl类来封装属性页控件的各种操作。通过调用
BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );创建一个窗口,dwStyle中可以使用以下一些属性页控件的专用风格:
TCS_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);
}
}
4.A 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菜单项。
在以后的章节4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar会给出使用的方法。