mfc mysql clistctrl_MFC总结之CListCtrl用法及技巧(二)

本篇重点介绍: 禁 止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题 。 6 、禁止拖动表头 重载 OnNotify 消息响应函数,屏蔽两个消息通知码: HDN_BEGINTRACKW 和 HDN_DIV

本篇重点介绍:禁止拖动表头、让第一列居中显示、设置行高与字体、虚拟列表技术、点击表头时进行归类、向上与向下移动、动态调整大小问题、避免闪烁问题。

6、禁止拖动表头

重载OnNotify消息响应函数,屏蔽两个消息通知码:HDN_BEGINTRACKW 和HDN_DIVIDERDBLCLICKW。示例如下:

[cpp]

view plaincopy

BOOLCXXXX::OnNotify(WPARAMwParam,LPARAMlParam,LRESULT* pResult)

{

// TODO: Add your specialized code here and/or call the base class

//屏蔽两个消息通知码,使得禁止拖动List表头

NMHEADER* pNMHeader = (NMHEADER*)lParam;

if(((pNMHeader->hdr.code == HDN_BEGINTRACKW) |

(pNMHeader->hdr.code == HDN_DIVIDERDBLCLICKW)))

{

*pResult = TRUE;

returnTRUE;

}

returnCDialog::OnNotify(wParam, lParam, pResult);

}

7、让第一列居中显示

在插入列时,我们可以通过参数nFormat来设置文本居中显示,但是这种设置对于第一列是没有作用的。这时我们可以考虑将我们的内容从第二列开始插入(设置为居中显示)。先插入第一列,然后删除第一列,这样原先的第二列就充当了第一列。

8、设置行高和字体

设置CListCtrl的行高没有函数接口,可以通过自绘来实现,但是比较麻烦。有一个比较简单的方法是通过使用一个空白的图像将行撑起来,使其高度发生变化。示例如下:

[cpp]

view plaincopy

CImageList m_image;

m_image.Create(1,24,ILC_COLOR32,1,0);

m_listInfo.SetImageList(&m_image, LVSIL_SMALL);

对于字体的设置,我们可以使用SetFont函数来实现。以修改CListView的字体为例,在OnInitialUpdate函数中插入列之前调用SetFontSelf函数(该函数自定义,如下示例所示)。首先创建一个字体,然后调用SetFont进行设置。需要注意的是,在退出时需要delete 掉创建的字体,避免内存泄露。

[cpp]

view plaincopy

//设置字体和大小

voidCMyListView::SetFontSelf(intnHeight,LPCTSTRlpszFacename)

{

//先删除原有字体

if(m_font != NULL)

deletem_font;

m_font = newCFont;

//创建字体

m_font->CreateFont(

nHeight, // nHeight

0, // nWidth

0, // nEscapement

0, // nOrientation

FW_NORMAL, // nWeight

FALSE, // bItalic

FALSE, // bUnderline

0, // cStrikeOut

ANSI_CHARSET, // nCharSet

OUT_DEFAULT_PRECIS, // nOutPrecision

CLIP_DEFAULT_PRECIS, // nClipPrecision

DEFAULT_QUALITY, // nQuality

DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily

lpszFacename); // lpszFacename

//设置字体

CListCtrl &theCtrl = GetListCtrl(); //获取控制权,引用变量

theCtrl.SetFont(m_font, TRUE);

}

9、虚拟列表技术

给一个链接,介绍的比较详细:http://hi.baidu.com/qi_xian/blog/item/929b04ce27d02c0592457ef8.html

当数据量大时,使用InsertItem插入数据的过程是很漫长的。这时我们有两个方法来解决该问题:一是使用CListCtrl的虚拟列表技术,二是采用分页显示的方法。对于虚拟列表技术,上述链接中的文章讲的很详细,我用过它的比较简单的方法,后来改用了分页方法。

使用虚拟列表技术,有三点需要搞清楚:

① 使用虚拟技术时,需要将CListCtrl控件的Owner Data属性设置为ture。

② 给虚拟列表添加元素时,不需要使用InserItem函数,通过调用SetItemCount设置数据总个数,然后由系统产生不同的消息,在相应的消息响应函数中完成插入工作。

③ 虚拟列表向父窗口发送的消息有三种: ⑴ 当它需要数据时,发送LVN_GETDISPINFO消息; ⑵ 当用户试图查找某个元素时,发送LVN_ODFINDITEM消息; ⑶当需要缓冲数据时,发送 LVN_ODCACHEHINT消息。

当我们使用LVN_GETDISPINFO 的消息处理函数来插入元素时,必须首先检查列表请求的是什么数据(如LVIF_TEXT、LVIF_IMAGE等),然后插入不同的子项。示例如下:

[cpp]

view plaincopy

voidCDataAnalysis::OnLvnGetdispinfoAnalysisList(NMHDR *pNMHDR,LRESULT*pResult)

{

NMLVDISPINFO *pDispInfo = reinterpret_cast(pNMHDR);

// TODO: Add your control notification handler code here

LV_ITEM* pItem= &(pDispInfo)->item;

intiItemIndex= pItem->iItem;

size_tconverted = 0;

wchar_twStr[30];//Unicode字符串

if(pItem->mask & LVIF_TEXT)//字符串缓冲区有效

{

switch(pItem->iSubItem)

{

case0://填充数据项的名字,xxxxx表示要填充的字符

mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);

lstrcpy(pItem->pszText,wStr);

break;

case1://填充子项1

mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);

lstrcpy(pItem->pszText,wStr);

break;

case2://填充子项2

mbstowcs_s(&converted, wStr, 30, xxxxxx, _TRUNCATE);

lstrcpy(pItem->pszText,wStr);

break;

case3://填充子项3

lstrcpy(pItem->pszText,xxxxxx);

break;

}

}

*pResult = 0;

}

10、点击表头时进行归类排序

系统通过发送LVM_SORTITEMS消息来处理归类问题,在该消息的处理函数中需要调用一个回调函数,这个回调函数需要我们来设计,以完成不同的归类方法。回调函数原型如下:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)

针对上述回调函数,有以下几点需要搞清楚:

① 对于参数lparam1和lparam2,分别为CListCtrl的两行数据,是用于比较的对象。通过CListCtrl的成员函数SetItemData来设置,该函数原型:

int SetItemData(int nIndex, DWORD_PTR dwItemData )

其第一个参数为行号,第二个参数指明了该行对应的参数。参数dwItemData 通常设为一行参数的数组,如: pData[2][2] = {{1, 3},{2, 3}}; 每次使用pData[i]作为dwItemData。

② 对于参数lParamSort,用于指明列项,即第几列。该参数和回调函数一同通过CListCtrl的成员函数SortItems来设置,其函数原型为:

BOOL SortItems( PFNLVCOMPARE pfnCompare,DWORD_PTR dwData )

参数 pfnCompare 为回调函数入口地址, 参数dwData 为列项。

③ SetItemData在初始插入数据时进行调用来设置,SortItems则在点击列表头时响应的消息处理函数中进行设置。

示例如下:

[cpp]

view plaincopy

//初始化列表视图控件

BOOLCDataAnalysis::InitListCtl()

{

//其他处理,包括设置风格,插入列等等

//插入行

for(inti=0; i

{

//要将char*转换为wchar_t*

mbstowcs_s(&converted, wStr, 30, m_analysis[i].Date, _TRUNCATE);

m_listAnalysis.InsertItem(i, wStr); //日期

mbstowcs_s(&converted, wStr, 30, m_analysis[i].Time, _TRUNCATE);

m_listAnalysis.SetItemText(i, 1, wStr); //时间

mbstowcs_s(&converted, wStr, 30, m_analysis[i].ID, _TRUNCATE);

m_listAnalysis.SetItemText(i, 2, wStr); //ID

m_listAnalysis.SetItemText(i, 3, m_analysis[i].lpszEvent); //事件

//设置回调函数的参数

m_listAnalysis.SetItemData(i, (LPARAM)(m_analysis+i));

}

returnTRUE;

}

voidCDataAnalysis::OnHdnItemclickAnalysisList(NMHDR *pNMHDR,LRESULT*pResult)

{

LPNMHEADER phdr = reinterpret_cast(pNMHDR);

// TODO: Add your control notification handler code here

//设置回调函数的参数和入口地址

m_listAnalysis.SortItems(SortFunc, phdr->iItem);

*pResult = 0;

}

//排序的回调函数

intCALLBACK SortFunc(LPARAMlParam1,LPARAMlParam2,LPARAMlParamSort)

{

intresult;//返回值

//两行的参数,用于比较

ANALYSISFORMAT* pAnalysis1 = (ANALYSISFORMAT*)lParam1;

ANALYSISFORMAT* pAnalysis2 = (ANALYSISFORMAT*)lParam2;

//排序

switch(lParamSort)

{

case0://日期

result = strcmp(pAnalysis1->Date, pAnalysis2->Date);

break;

case1://时间

result = strcmp(pAnalysis1->Time, pAnalysis2->Time);

break;

case2://ID

result = strcmp(pAnalysis1->ID, pAnalysis2->ID);

break;

case3://事件

result = wcscmp(pAnalysis1->lpszEvent, pAnalysis2->lpszEvent);

break;

default:

break;

}

returnresult;

}

11、向上与向下移动

有时需要向上或向下移动表项内容,这里给出向上移动的方法,向下移动的方法类似。

① 利用第2节所述的内容获取行号nItem,判断行号是否为行首,如果不是行首则进入②;

② 获取第nItem行的所有子项内容;

③ 删除第nItem行,并在nItem-1的位置重新插入原先的第nItem行的内容;

④ 使nItem-1的位置高亮显示

示例如下:

[cpp]

view plaincopy

/*************************上移子项**************************/

voidCStudyTestDlg::OnPageup()

{

if(nItem == 0)

{

MessageBox("该子项已经位于第一行!");

return;

}

// 提取内容

CString temp[4];

inti;

for(i=0;i<4;i++)

temp[i] = m_ListCtrl.GetItemText(nItem, i);

// 删除

m_ListCtrl.DeleteItem(nItem);

// 在nItem-1位置处插入

for(i=0; i<4; i++)

m_ListCtrl.SetItemText(nItem-1,i,temp[i]);

//高亮显示

UINTflag = LVIS_SELECTED|LVIS_FOCUSED;

m_ListCtrl.SetItemState(--nItem, flag, flag);

}

/*************************下移子项**************************/

voidCStudyTestDlg::OnPagedown()

{

if(nItem == m_ListCtrl.GetItemCount()-1)

{

MessageBox("该子项已经位于最后一行!");

return;

}

// 提取内容

CString temp[4];

inti;

for(i=0; i<4; i++)

temp[i] = m_ListCtrl.GetItemText(nItem, i);

// 删除

m_ListCtrl.DeleteItem(nItem);

// 在nItem+1位置处插入

for(i=0; i<4; i++)

m_ListCtrl.SetItemText(nItem+1, i,temp[i]);

//高亮显示

UINTflag = LVIS_SELECTED|LVIS_FOCUSED;

m_ListCtrl.SetItemState(++nItem, flag, flag);

}

12、避免闪烁问题

这个问题在我的前面一篇博文有提到。

http://blog.csdn.net/zwgdft/article/details/7394318

13、动态调整大小

有时由于不确定软件运行时的电脑屏幕大小,需要根据屏幕大小动态设置CListCtrl控件的大小。动态大小的设置时,需要注意不要将高度和宽度设置的超过区域限制,否则就没有滚动条了,导致部分内容无法查看。以我遇到的一个例子来说,其情况见第12节提到的那篇博文所述:将View划分为三个窗格,在左上角View上有个CPropertySheet,其上有几个CPropertyPage,每个属性页上有个CListCtrl,供用户查看信息。那么这时需要设置的CListCtrl的大小即为:

宽度 = 左上角View宽度

高度 = 左上角View高度 - 属性页的Tab项高度

调用MoveWindow函数进行设置即可。

------------------全文完--------------------

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值