MFC中listctrl的补充介绍

    xiaoxiao2026-05-14  10

    一.实现单击或双击CListCtrl控件的某一行或某一列对应的事件被触发、相应的函数被调用。

    头文件:

    public:

    afx_msg void OnNMClickReasonList(NMHDR *pNMHDR, LRESULT *pResult);//单击

    afx_msg void OnNMDblClickReasonList(NMHDR *pNMHDR, LRESULT *pResult);//双击

    cpp文件:

    BEGIN_MESSAGE_MAP(XxxDlg, Xxx)     ON_NOTIFY(NM_CLICK, IDC_REASON_LIST, &XxxDlg::OnNMClickReasonList)//单击

        ON_NOTIFY(NM_DBLCLK,IDC_REASON_LIST, &XxxDlg::OnNMDblClickReasonList)//双击 END_MESSAGE_MAP()

    //Click different rows of the list control to update corresponding strResolveMethod value and show it on the edit box. void ReasonMethodShowDlg::OnNMClickReasonList(NMHDR *pNMHDR, LRESULT *pResult)//单击 {     LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);     // TODO: Add your control notification handler code here     int row = pNMItemActivate->iItem;//行号

        int col = pNMItemActivate->iSubItem;//列号

        ...

        *pResult = 0; }

    void ReasonMethodShowDlg::OnNMClickReasonList(NMHDR *pNMHDR, LRESULT *pResult)//双击 {     LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);     // TODO: Add your control notification handler code here     int row = pNMItemActivate->iItem;//行号

        int col = pNMItemActivate->iSubItem;//列号

        ...

        *pResult = 0; } 对于多行多列可能出现的错误情况参考如下代码:

    1.POINT ptMouse; GetCursorPos(&ptMouse); m_List.ScreenToClient(&ptMouse); int iSelected = m_List.HitTest(ptMouse,0);

    2.LPNMLVCUSTOMDRAW lplvcd =  reinterpret_cast <LPNMLVCUSTOMDRAW>(pNMHDR); int  iRow = lplvcd->nmcd.dwItemSpec; int  iCol = lplvcd->iSubItem;

    以及CListCtrl扩展类资料:http://download.csdn.net/detail/paschen/8927009

    二.让CListCtrl控件指定的行高亮显示。

    先给listctrl加上show selection always 属性,给CListCtrl控件添加绑定变量m_list

    头文件:

    private:

    CListCtrl m_list;

    cpp文件:

    void XxxDlg::DoDataExchange(CDataExchange* pDX) {     CPropertyPage::DoDataExchange(pDX);     DDX_Control(pDX, IDC_REASON_LIST, m_list); }

    然后设置list模块状态:m_list.SetItemState(0, LVIS_SELECTED,LVIS_SELECTED);

    如果要蓝色高亮显示,在前面加上m_list.SetFocus();让listctrl获得真正的焦点。

    三.让CListCtrl控件每行中间显示分隔线。    

    m_list.SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT);

    四.让CListCtrl控件的横竖滚动条根据显示的内容长度自动显示与消失。

    m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);

    五.让CListCtrl控件的列头部标题隐藏起来。

    设置listctrl控件的No Column Header值为True。

    下面是汇总的函数,放在类的OnInitDialog函数中即可:

        void XxxDlg::createList() {     int reasonId;     OutputContentManagement outputContentManagement = ((CPDLAnalysisApp*)AfxGetApp())->outputContentManagement;     //Load the reason content of the list control.     m_list.InsertColumn(0,_T("障害原因"));     for(reasonId = 0;reasonId<REASON_NUM;reasonId++)     {         strReason = outputContentManagement.getReason(reasonId);         m_list.InsertItem(reasonId, strReason);     }     m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);     m_list.SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT);     m_list.SetFocus();     m_list.SetItemState(0, LVIS_SELECTED,LVIS_SELECTED);     //Set the default resolve method.     strResolveMethod = outputContentManagement.getResolveMethod(0);     UpdateData(FALSE); }

    给list ctrl添加不同模式下的图标和文字内容:

    在ListCttrl控件(Report风格)的使用上,有时需要向子列中插入图标,例如要制作一个下载软件,我们计划在控件的第一列用图标的形式显示下载状态:排队、下载中、出错等等,第二列计划用图标显示下载文件类型,要做出这样的效果,就必须使用CListCtrl的SetItem(八个参数)方法,由于我这台电脑上没有MSDN所以这八个参数具体都是什么意思我暂时不清楚,在这只介绍下跟我们的操作关系密切的几个参数。

    SetItem()从左向右数第一个参数(从1起计数)表示操作行的行号,这个行号从0计数,最好这个参数设置为InsertItem()的返回值,也就是说应该先用InsertItem()插入一个空行,之后用SetItemText()具体设置插入行每一列的值。SetItem()的第二个参数表示即将操作的列号,也就是我们打算将图标插入到第几列中,该行号从0计数。SetItem()的第五个参数表示图标在CImageList对象(该对象已经通过SetImageList(&ImageList, LVSIL_SMALL)附属至CListCtrl控件)中的序数,该序数从0计数,顺便说一句,准备附属到CListCtrl控件的CImageList对象必须是全局性的,比如可以是类的成员,否则就算其他操作都都正确也看不到图标。

    举个例子我们使用的CListCtrl控件的控制对象为m_List,m_List中已经添加了三个列,IDX是InsertItem()的返回值,表示刚刚插入的新行,附属到m_List的CImageList对象中有5个图标,我们通过m_List.SetItem(IDX, 0, LVIF_IMAGE, NULL, 1, 0, 0, 0);之后,就把CImageList对象中的第1个图标插在了第一列的前部(原先第一列的文字还在),之后接着通过m_List.SetItem(IDX, 2, LVIF_IMAGE, NULL, 0, 0, 0, 0);就把CImageList对象中的第0个图标插在了第二列的前部(原先的文字还在)。可以看到如下实例图:

    有一点值得说明,如果只在子列中插入了图标而没有给主列(第一列)插入任何图标,则默认第一列将插入与同一行最后一次给子列插入图标。 还有重要的一点,如果想在子列插入图标,首先必须使ListCtrl控件具备LVS_EX_SUBITEMIMAGES风格,例如我们可以通过m_List.SetExtendedStyle(m_List.GetExtendedStyle()|LVS_EX_SUBITEMIMAGES);给控件附加该风格。 注意事项:如果插入后没有显示 或者是 显示的不是预想的图标 很有可能是图片的属性 和 CImageList创建的时候不相符合 比如 m_imglist.Create(66, 16, ILC_COLORDDB,0,0); 如果你插入的BMP不是66X16大小 很有可能就会插入失败 而且这里是可能失败 这样就造成了 不会报错 但是图标显示的结果有可能和想要的不通 至于哪些图标可以显示 哪些不能显示 这个就不容易看出来 而且如果第一张插入失败了 第二张插入成功 在显示图标的时候 第二张就变成第一张了 比较隐含的错误 一定注意! //

    一.CListCtrl在第一列添加图标

    CListCtrl可以很方便的在第一列添加图标, 并且在不同的显示方式(1:LVS_ICON: 为每个item显示大图标;2:LVS_SMALLICON: 为每个item显示小图标;3: LVS_LIST: 显示一列带有小图标的item;4:LVS_REPORT: 显示item详细资料)下, 都可以把第一列的图标显示出来.。

    具体方法为:

    1.在Dialog的头文件中声明CListCtrl控件和CImageList类变量

    CListCtrl       m_lstEnumDev;                   CImageList    m_SmallIcon;                     //保存小图标 CImageList    m_LargeIcon;                    //保存大图标

    2.在Dialog的OnInitDialog()中

    /*******设置列表表头内容和宽度*****/ m_lstEnumDev.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT |   LVS_EDITLABELS|   LVS_EX_SUBITEMIMAGES );             //一定要设置LVS_EX_SUBITEMIMAGES m_lstEnumDev.InsertColumn(0,"名称");     m_lstEnumDev.SetColumnWidth(0,80); 。。。。。。

     /**********绑定SmallIcon和LargeIcon到CListCtrl上******/  m_SmallIcon.Create(16,16, 1, 10, 4);  m_LargeIcon.Create(32,32, 1, 10, 4);  m_SmallIcon.Add(AfxGetApp()->LoadIcon(IDI_ICON_SMALL));  m_LargeIcon.Add(AfxGetApp()->LoadIcon(IDI_ICON_LARGE)); m_lstEnumDev.SetImageList(&m_LargeIcon,LVSIL_NORMAL);   m_lstEnumDev.SetImageList(&m_SmallIcon,LVSIL_SMALL);、

     /********显示列表中的信息*********/  ShowListInfo(); 

     3.在ShowListInfo()中显示列表中的信息

    for (int i=0;i<iItemNum;i++) {    //名称   LV_ITEM lvitem;   memset ((char *) &lvitem, '\0', sizeof (LV_ITEM));   lvitem.mask = LVIF_TEXT | LVIF_IMAGE  | LVIF_STATE;   lvitem.iItem = i;   lvitem.iSubItem = 0;   lvitem.stateMask = 0;   lvitem.iImage = 0;          //显示不同的图标时,可以把一个int 变量赋给这个属性值   lvitem.pszText = "名称";   m_lstEnumDev.InsertItem (&lvitem); }

    实现以上3步,就可以显示带图标的文本项了。

    4.可在Dialog的头文件中声明CComboBox m_cmbViewType变量,控制不同的显示方式。

     /******初始化下拉列表*****/  m_cmbViewType.AddString("详细信息");  m_cmbViewType.AddString("平铺");  m_cmbViewType.AddString("图标");  m_cmbViewType.AddString("列表");  m_cmbViewType.SetCurSel(0);

    5.相应CComboBox的CBN_SELCHANGE消息,实现不同的显示方式

     int nSel = m_cmbViewType.GetCurSel();  switch(nSel)  {  case 0:   m_lstEnumDev.ModifyStyle ( LVS_SMALLICON | LVS_LIST | LVS_ICON,LVS_REPORT, TRUE);   break;  case 1:         m_lstEnumDev.ModifyStyle ( LVS_SMALLICON | LVS_LIST | LVS_REPORT,LVS_ICON, TRUE);    break;  case 2:         m_lstEnumDev.ModifyStyle (LVS_ICON | LVS_LIST | LVS_REPORT | LVS_OWNERDRAWFIXED, LVS_SMALLICON, TRUE);      break;  case 3:   m_lstEnumDev.ModifyStyle (LVS_ICON | LVS_SMALLICON | LVS_REPORT | LVS_OWNERDRAWFIXED, LVS_LIST, TRUE);      break;  default:   m_lstEnumDev.ModifyStyle ( LVS_SMALLICON | LVS_LIST | LVS_ICON,LVS_REPORT, TRUE);      break;  }

    经过以上5步,即可实现,在不同的显示方式下,使列表的第一列显示(相同或不同的)图标。

     二.CListCtrl非第一列添加图标

    如果除了要使第一列显示图标外,还要使也其他列显示。只需要按照第一列那样声明一个LV_ITEM    lvitem;

      lvitem.mask = LVIF_TEXT | LVIF_IMAGE  | LVIF_STATE;   lvitem.iItem = i;   lvitem.iSubItem = j;   //列数   lvitem.stateMask = 0;//显示不同的图标时,可以把一个int 变量赋给这个属性值   lvitem.iImage = 0; 

    如果只让非第一列显示图标,就会出现一个问题——CImageList是和CListCtrl的第一列绑定的,这个第一列是逻辑上的。

    那可不可以使(视图上的)非第一列变成(逻辑上的)的第一列呢? 我的实现思想是:显示在视图上的非第一列其实是CListCtrl的逻辑上的第一列,即:m_lstEnumDev.InsertColumn(0,"名称");这个" 0" 其实就是逻辑上的第一列。

    那该怎么实现呢? 我的实现思想是:使第一列和其他的某列交换位置。调用了CListCtrl 的GetHeaderCtrl()方法,通过表头控件CHeaderCtrl的SetOrderArray设置(视图上的)显示顺序。

     /*******第一和最后一列交换位置***/   CHeaderCtrl *pmyHeaderCtrl = m_lstEnumDev.GetHeaderCtrl();  int   nCount   =   pmyHeaderCtrl->GetItemCount();    LPINT   pnOrder   =   (LPINT)   malloc(nCount*sizeof(int));    ASSERT(pnOrder   !=   NULL);        pmyHeaderCtrl->GetOrderArray(pnOrder,   nCount);     int nTemp;  nTemp     = pnOrder[0];  pnOrder[0]        =   pnOrder[nCount-1];    pnOrder[nCount-1] = nTemp;

     pmyHeaderCtrl->SetOrderArray(nCount,   pnOrder);    free(pnOrder);

    这样再显示时,在视图上,第一列就变成最后一列了。当选择不同的显示方式时,都可以看到图标。
    转载请注明原文地址: https://ju.6miu.com/read-1309660.html
    最新回复(0)