CTreeCtrl 和 CListCtrl 控件(VC_MFC)

目录

Tree Control 控件
List Control 控件

(本章节中例子都是用 VS2005 编译调试的)


Tree Control 控件(MSDN 链接)

说明:

树形控件是用于构造树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子结点上有允许有一个或多个或没有子结点.在树形控件中每一个结点都有一个句柄(HTREEITEM),同时添加结点时必须提供该结点的父结点句柄(其中根Root结点只有一个,既不可以添加也不可以删除), MFC 中使用 CTreeCtrl 类来封装树形控件的各种操作.树形控件的消息映射使用 ON_NOTIFY 宏.

三个重要结构:

TVINSERTSTRUCT(MSDN 链接)

作用:  这个结构体包含了在树形图控件添加子节点时需要的相关信息

结构体定义:

View Code
typedef struct _TV_INSERTSTRUCT { 
HTREEITEM hParent; // Handle to the parent item
HTREEITEM hInsertAfter; // Handle to the item after which the new item is to be inserted
TV_ITEM item; // TV_ITEM structure that contains information about the item to add
} TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;

TVITEM(MSDN 链接)

作用:  记录着被添加的数的节点的信息

结构体定义:

View Code
typedef struct _TV_ITEM { //tvi
UINT mask; // ndicates which of the other structure members contain valid data
HTREEITEM hItem; // Handle to the item to which this structure refers
UINT state; // Set of bit flags and image list indexes that indicate the item's state
UINT stateMask; // Bits of the state member that are valid
LPSTR pszText; // Pointer to a null-terminated string that contains the item text
int cchTextMax; // Size of the buffer pointed to by the pszText member
int iImage; // Index in the tree view control's image list of the icon image to use when the item is in the nonselected state
int iSelectedImage; //Index in the tree view control's image list of the icon image to use when the item is in the selected state.
int cChildren; // Indicates whether the item has associated child items
LPARAM lParam;  // Specifies a 32-bit value to associate with the item.
}TV_ITEM, FAR *LPTV_ITEM;

NMTREEVIEW(MSDN 链接)

作用:  包含关于树形视通知消息的信息

结构体定义:

View Code
typedef struct _NM_TREEVIEW { 
  NMHDR hdr; // NMHDR structure that contains information about this message
  UINT action; // Notification-specific action flag
  TV_ITEM itemOld; // TV_ITEM structure that contains information about the old item state
  TV_ITEM itemNew; // TV_ITEM structure that contains information about the new item state.
  POINT ptDrag; // POINTstructure that contains the client coordinates of the mouse at the time the event occurred that caused the message to be sent
} NM_TREEVIEW;
typedef NM_TREEVIEW FAR* LPNM_TREEVIEW;

CTreeCtrl 常用函数(单击函数链接至MSDN):

  • 创建树形结构控件窗口:  Create

    在 Create 中 dwStyle 中可以使用以下一些树形控件的专用风格:

    TVS_HASLINES   在父/子结点之间绘制连线
    TVS_LINESATROOT   在根/子结点之间绘制连线
    TVS_HASBUTTONS   在每一个结点前添加一个按钮,用于表示当前结点是否已被展开
    TVS_EDITLABELS   结点的显示字符可以被编辑
    TVS_SHOWSELALWAYS   在失去焦点时也显示当前选中的结点
    TVS_DISABLEDRAGDROP   不允许Drag/Drop
    TVS_NOTOOLTIPS   不使用ToolTip显示结点的显示字符

  • 插入字节点:  InsertItem
  • 获得 / 设置节点图标:  GetImageList / SetImageList
  • 获得 / 设置选中结点:  GetSelectedItem / SelectItem 
  • 获得 / 修改索引结点图标:   GetItemImage / SetItemImage
  • 获得 / 修改结点的显示字符:  GetItemText / SetItemText
  • 删除结点:  DeleteItem
  • 将删除所有结点:  DeleteAllItems
  • 获得根结点:  GetRootItem
  • 获得节点父 / 子结点:  GetParentItem / GetChildItem
  • 获得结点的上 / 下一个兄弟结点:  GetPrevSiblingItem / GetNextSiblingItem 
  • 获得 / 设置控件背景色:  GetBkColor / SetBkColor
  • 获得 / 设置节点属性:  GetItem / SetItem
  • 获得 / 设置控件字体颜色:  GetTextColor / SetTextColor
  • 获得节点矩形区:  GetItemRect

代码示例:

[插入节点][插入带图标的节点]

插入节点

先在主对话框中拖入一个 Tree Control 控件,,然后为这个控件添加控制变量其变量类型为 CTreeCtrl 类和名为 m_tc.资源视图如下:

为这个控件添加子节点,节点结构为如下所示:

+--- Parent1
  +--- Child1_1
  +--- Child1_2
+--- Parent2
  +--- Child2_1

在对话框的初始化函数(即 OnInitDialog 函数)添加相关的实现代码,如下:

View Code
//声明指向节点的句柄
HTREEITEM hItem,hSubItem;

//插入节点
//在根结点上添加 Parent1
hItem = m_tc.InsertItem(L"Parent1",TVI_ROOT);
//在 Parent1 上添加一个子结点 Child1_1
hSubItem = m_tc.InsertItem(L"Child1_1",hItem);
// 在 Parent1 上添加一个子结点Child1_2,排在 Child1_1 后面
hSubItem = m_tc.InsertItem(L"Child1_2",hItem,hSubItem);
//在根结点上添加 Parent2
hItem = m_tc.InsertItem(L"Parent2",TVI_ROOT,hItem);
//在 Parent2 上添加一个子结点 Child2_1
m_tc.InsertItem(L"Child2_1",hItem);

运行结果:

若将控件 Tree Control 的 Has Buttons , Has Lines 和 Lines At Root 设置为 true,则控件效果为如下所示:

插入有带图标的节点

先在主对话框中拖入一个 Tree Control 控件,然后为这个控件添加控制变量其变量类型为 CTreeCtrl 类和名为 m_tc.和两个图标资源(IDI_ICON1 和 IDI_ICON2)资源视图如下:

  

然后将控件 Tree Control 的 Has Buttons , Has Lines 和 Lines At Root 设置为 true. 并为这个控件添加子节点,节点结构为如下所示:

+--- Parent1
  +--- Child1_1
  +--- Child1_2
+--- Parent2
  +--- Child2_1

在对话框的初始化函数(即 OnInitDialog 函数)添加相关的实现代码,如下:

View Code
//载入图标
HICON icon[2];
icon[0]=AfxGetApp()->LoadIcon (IDI_ICON1); 
icon[1]=AfxGetApp()->LoadIcon (IDI_ICON2);

//创建图像列表控件
CImageList *imagelist=new CImageList; 
imagelist->Create(16,16,0,7,7); 
imagelist->SetBkColor (RGB(255,255,255));
for(int n=0;n<2;n++)
{
    //把图标载入图像列表控件
    imagelist->Add(icon[n]); 
}
//为 m_tc 设置一个图像列表,使 Tree Control 控件的节点显示不同的图标
m_tc.SetImageList(imagelist,TVSIL_NORMAL);  

//声明指向节点的句柄
HTREEITEM hItem,hSubItem;

//插入节点
//在根结点上添加 Parent1
hItem = m_tc.InsertItem(L"Parent1",TVI_ROOT);
//在 Parent1 上添加一个子结点 Child1_1
hSubItem = m_tc.InsertItem(L"Child1_1",hItem);
// 在 Parent1 上添加一个子结点Child1_2,排在 Child1_1 后面
hSubItem = m_tc.InsertItem(L"Child1_2",hItem,hSubItem);
//在根结点上添加 Parent2
hItem = m_tc.InsertItem(L"Parent2",TVI_ROOT,hItem);
//在 Parent2 上添加一个子结点 Child2_1
m_tc.InsertItem(L"Child2_1",hItem);

运行结果:

相关文章:

树形图的使用详解

在MFC中应用CTreeCtrl控件的技巧


List Control 控件(MSDN 链接)

两个重要结构:

LVCOLUMN(MSDN 链接)

作用:  这个结构体记录了列的相关信息

结构体定义:

View Code
typedef struct _LVCOLUMN {
  UINT   mask; // Variable specifying which members contain valid information
  int    fmt; // Alignment of the column header and the subitem text in the column
  int    cx; // Width of the column, in pixels
  LPTSTR pszText; // contains the column header text.
  int    cchTextMax; // Size in TCHARs of the buffer pointed to by the pszText member
  int    iSubItem; // Index of subitem associated with the column.
#if (_WIN32_IE >= 0x0300)
  int    iImage; // Zero-based index of an image within the image list. The specified image will appear within the column.
  int    iOrder; // Zero-based column offset. Column offset is in left-to-right order. For example, zero indicates the leftmost column.
#endif 
#if (_WIN32_WINNT >= 0x0600)
  int    cxMin; // Minimum width of the column in pixels.
  int    cxDefault; // Application-defined value typically used to store the default width of the column. This member is ignored by the list-view control.
  int    cxIdeal; // Read-only. The ideal width of the column in pixels, as the column may currently be autosized to a lesser width.
#endif 
} LVCOLUMN, *LPLVCOLUMN;

LVITEM(MSDN 链接)

作用:  这个结构体记录了行的相关信息

结构体定义:

View Code
typedef struct {
  UINT   mask; // Set of flags that specify which members of this structure contain data to be set or which members are being requested
  int    iItem; // Zero-based index of the item to which this structure refers
  int    iSubItem; // One-based index of the subitem to which this structure refers, or zero if this structure refers to an item rather than a subitem
  UINT   state; // Indicates the item's state, state image, and overlay image
  UINT   stateMask; // Value specifying which bits of the state member will be retrieved or modified
  LPTSTR pszText; // containing the item text
  int    cchTextMax; // Number of TCHARs in the buffer pointed to by pszText, including the terminating NULL.
  int    iImage; // Index of the item's icon in the control's image list.
  LPARAM lParam; // Value specific to the item. If you use the LVM_SORTITEMS message, the list-view control passes this value to the application-defined comparison function.
#if (_WIN32_IE >= 0x0300)
  int    iIndent; // Number of image widths to indent the item. A single indentation equals the width of an item image
#endif 
#if (_WIN32_WINNT >= 0x0501)
  int    iGroupId; //  Identifier of the group that the item belongs to, or one of the following values.
  UINT   cColumns; // Number of data columns (subitems) to display for this item in tile view.
  UINT   puColumns; // A pointer to an array of column indices, specifying which columns are displayed for this item, and the order of those columns.
#endif 
#if (_WIN32_WINNT >= 0x0600)
  int    piColFmt; // A pointer to an array of the following flags (alone or in combination), specifying the format of each subitem in extended tile view.
  int    iGroup; // Group index of the item.
#endif 
} LVITEM, *LPLVITEM;

CListCtrl 常用函数(单击函数链接至MSDN):

  • 插入 / 删除列:  InsertColumn / DeleteItem
  • 插入 / 删除行:  InsertItem / DeleteColumn
  • 删除所有行:  DeleteAllItems
  • 获得 / 设置行图标:  GetImageList / SetImageList
  • 获得 / 更改行位置:  GetItemPosition / SetItemPosition
  • 获得 / 设置行文本:  GetItemText / SetItemText
  • 获得 / 设置列宽度:  GetColumnWidth / SetColumnWidth
  • 获得 / 设置控件扩展风格:  GetExtendedStyle / SetExtendedStyle
  • 获得 / 设置列属性:  GetColumn / SetColumn
  • 获得 / 设置控件背景图片:   GetBkImage / SetBkImage
  • 获得 / 设置控件背景颜色:  GetBkColor / SetBkColor
  • 获得 / 设置文本颜色:  GetTextColor / SetTextColor
  • 获得 / 设置文本背景色:  GetTextBkColor / SetTextBkColor
  • 获得字符串宽度:  GetStringWidth
  • 获得 / 设置行属性:  GetItem / SetItem
  • 获得某行矩形区域:  GetItemRect
  • 获得 / 设置行状态:  GetItemState / SetItemState  (在 SetItemState 中的两个参数取值说明 nState , nMask )
  • 获得控件行总数:  GetItemCount
  • 获得选中行索引(当时索引不是基于 0 而是基于 1):  GetFirstSelectedItemPosition

代码样例:

[插入行][插入带图标的行][在 View 值为 Report 下设置多列样式][设置控件样式][使控件在失去焦点时候依旧高亮显示]

插入行

先在主对话框中拖入一个 List Control 控件(View 属性为 Icon),然后为这个控件添加控制变量其变量类型为 CListCtrl 类和名为 m_lc.资源视图如下:

然后,在对话框初始化函数(即函数 OnInitDialog 中)向控件中插入"T_1","T_2","T_3","T_4","T_5","T_6","T_7","T_8","T_9","T_0" 10 行数据,具体代码如下:

View Code
//插入列,列属性只对 View 属性值为 Report 时才起作用
//并且在 Report 下不能不插入列,不然显示不出任何东西 
m_lc.InsertColumn(0, L"ColumnName",LVCFMT_LEFT,100);
//插入行
 m_lc.InsertItem(0, L"T_1");
 m_lc.InsertItem(1, L"T_2");
 m_lc.InsertItem(2, L"T_3");
 m_lc.InsertItem(3, L"T_4");
 m_lc.InsertItem(4, L"T_5");
 m_lc.InsertItem(5, L"T_6");
 m_lc.InsertItem(6, L"T_7");
 m_lc.InsertItem(7, L"T_8");
 m_lc.InsertItem(8, L"T_9");
 m_lc.InsertItem(9, L"T_0");

运行结果:

若将控件的 View 属性设置 Small Icon,List 或 Report 时的效果如下:

插入有带图标的行

先在主对话框中拖入一个 List Control 控件(View 属性为 Icon,若为其他图标则显示不出来),然后为这个控件添加控制变量其变量类型为 CListCtrl 类和名为 m_lc.和两个图标资源(IDI_ICON1 和 IDI_ICON2)资源视图如下:

然后为在对话框初始化函数(即函数 OnInitDialog 中)向控件中插入"T_1","T_2" 2行带有图标的数据,具体代码如下:

View Code
//载入图标
HICON icon[2];
icon[0]=AfxGetApp()->LoadIcon (IDI_ICON1); 
icon[1]=AfxGetApp()->LoadIcon (IDI_ICON2);

//创建图像列表控件
CImageList *imagelist=new CImageList; 
imagelist->Create(16,16,0,7,7); 
imagelist->SetBkColor (RGB(255,255,255));
for(int n=0;n<2;n++)
{
    //把图标载入图像列表控件
    imagelist->Add(icon[n]); 
}

//为 m_lc 置一个图像列表,使 List Control 的行显示不同的图标
m_lc.SetImageList(imagelist,TVSIL_NORMAL);

// 插入行
m_lc.InsertItem(0, L"T_1",0);
m_lc.InsertItem(1, L"T_2",1);

运行结果:

在 View 值为 Report 下设置多列样式 

在插入数据前大致步骤如上,只需把对话框的 View 属性设置为 Report 然后,先添对列进行添加操作(即插入列)后等列都设置好了后,再进行行插入,实现代码依旧是在初始对话框的函数中(即函数 OnInitDialog 中),具体代码如下:

View Code
//插入列,列属性只对 View 属性值为 Report 时才起作用
//并且在 Report 下不能不插入列,不然显示不出任何东西 
m_lc.InsertColumn(0, L"ColumnName",LVCFMT_LEFT,100);
m_lc.InsertColumn(1,L"ColumnValue",LVCFMT_LEFT,100);
/* 插入行 **************************************************/
int i = m_lc.InsertItem(0, L"T_1");
//在非 Report 下这个文本数据是不显示的
//设置第二列数据
m_lc.SetItemText(i,1,L"One");

i = m_lc.InsertItem(1, L"T_2");
m_lc.SetItemText(i,1,L"Two");

i = m_lc.InsertItem(2, L"T_3");
m_lc.SetItemText(i,1,L"Three");

i = m_lc.InsertItem(3, L"T_4");
m_lc.SetItemText(i,1,L"Four");

i = m_lc.InsertItem(4, L"T_5");
m_lc.SetItemText(i,1,L"Five");

i = m_lc.InsertItem(5, L"T_6");
m_lc.SetItemText(i,1,L"Six");

i = m_lc.InsertItem(6, L"T_7");
m_lc.SetItemText(i,1,L"Seven");

i = m_lc.InsertItem(7, L"T_8");
m_lc.SetItemText(i,1,L"Eight");

i = m_lc.InsertItem(8, L"T_9");
m_lc.SetItemText(i,1,L"Nine");

i = m_lc.InsertItem(9, L"T_0");
m_lc.SetItemText(i,1,L"Zero");

运行结果:

设置控件样式

利用 SetExtendedStyle 来设置控件的扩展样式.List Control 具体的扩展样式(MSDN 链接)

我们来将控件设置一个具有整行高亮的属性且具有网格线并把实现添加至初始对话框的函数中(即函数 OnInitDialog 中).具体实现代码如下:

View Code
//获得控件扩展属性
DWORD dwStyle = m_lc.GetExtendedStyle();

//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_FULLROWSELECT;
//网格线(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;    

//设置控件扩展属性  
m_lc.SetExtendedStyle(dwStyle); 

//插入列,列属性只对 View 属性值为 Report 时才起作用
//并且在 Report 下不能不插入列,不然显示不出任何东西 
m_lc.InsertColumn(0, L"ColumnName",LVCFMT_LEFT,100);
m_lc.InsertColumn(1,L"ColumnValue",LVCFMT_LEFT,100);
/* 插入行 **************************************************/
int i = m_lc.InsertItem(0, L"T_1");
//在非 Report 下这个文本数据是不显示的
//设置第二列数据
m_lc.SetItemText(i,1,L"One");

i = m_lc.InsertItem(1, L"T_2");
m_lc.SetItemText(i,1,L"Two");

运行结果(为最右图,前两个图只是为了比较在添加了对应属性的和为添加的区别):

使控件在失去焦点时候依旧高亮显示

方法一:

为 List Control 控件添加 NM_CUSTOMDRAW 事件,并为事件添加如下代码:(其中有两个关键的结构体< NMHDR 和 NMLVCUSTOMDRAW> 点击其参看详细说名)

View Code
void CtestDlg::OnNMCustomdrawProtocol(NMHDR *pNMHDR, LRESULT *pResult)
{
    //LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    //*pResult = 0;

    //将 pLVCD 指向参数 pNMHDR 转换为 NMLVCUSTOMDRAW 类型的对象
    NMLVCUSTOMDRAW* pLVCD = reinterpret_cast( pNMHDR );
    *pResult = CDRF_DODEFAULT;

    if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
        *pResult = CDRF_NOTIFYITEMDRAW;
    else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
        *pResult = CDRF_NOTIFYSUBITEMDRAW;
    //当行被重绘时候
    else if ( (CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage )
    {
        COLORREF clrNewTextColor, clrNewBkColor;
        
        //获得要重绘的行的索引
        int nItem = static_cast<int>( pLVCD->nmcd.dwItemSpec );
        
        BOOL bSelect = FALSE;
        
        //获得选择行的位置
        POSITION pos =m_lc.GetFirstSelectedItemPosition()-1;  
  
        //若为重绘的该项为选中项 bSelect 为 true
        if((int)pos==nItem)   
            bSelect = TRUE;  

        //判断要重绘的项是否为选中项
        if(bSelect)
        {
            //为选中的行文本的背景色和前景初始化
            clrNewTextColor = RGB(255,255,255);
            clrNewBkColor = RGB(53,153,251);
        }
        else
        {
            //为未选中的行文本的背景色和前景初始化
            clrNewTextColor = RGB(0,0,0);
            clrNewBkColor = RGB(255,255,255);
        }
        //设置控件文本和文本背景色
        pLVCD->clrText = clrNewTextColor;
        pLVCD->clrTextBk = clrNewBkColor;

        *pResult = CDRF_DODEFAULT;
    }
}

这里也可以实现行颜色和选中行颜色的自定义.即对上面中的一下代码颜色值进行调整即可:

View Code
if(bSelect)
{
    //通过调整下面两个变量的 RGB 值实现自定义选中的行文本的背景色和前景色
    clrNewTextColor = RGB(255,255,255);
    clrNewBkColor = RGB(53,153,251);
}
else
{
    //通过调整下面两个变量的 RGB 值实现自定义未选中的行文本的背景色和前景色
    clrNewTextColor = RGB(0,0,0);
    clrNewBkColor = RGB(255,255,255);
}

运行结果与方法二一样

方法二:

为 List Control 控件添加 NM_KILLFOCUS 和 NM_SETFOCUS 事件,然后在对话框框中添加一个整形变量 m_SecCount.

接着在 NM_KILLFOCUS 和 NM_SETFOCUS 事件响应函数中添加如下代码:( SetItemState 相关说明参看上面)

View Code
/* NM_KILLFOCUS 事件响应函数中添加代码 *******************************************/    
//获得选中行的索引
m_SecCount = (int)m_lc.GetFirstSelectedItemPosition()-1;

//设置选中行一直高亮显示
m_lc.SetItemState(m_SecCount,LVIS_DROPHILITED,LVIF_STATE);



/* NM_SETFOCUS 事件响应函数中添加代码 *******************************************/    
//取消在失去高亮时候选中行的高亮显示
m_lc.SetItemState(m_SecCount,FALSE,LVIF_STATE);

运行结果:

相关文章:

CListCtrl 如何在失去焦点后行仍高亮显示

如何让 ListCtrl 控件失去焦点后还高亮

MFC 中 List Control 控件的使用

你可能感兴趣的:(CTreeCtrl 和 CListCtrl 控件(VC_MFC))