一个虚拟列表视的快速查找问题,用FindItem(&info)好象不行,请高手指教!

Renewal 2006-11-01 05:54:52
因为列表框里需要显示的数据多达10万条或者几十万,我不得不用虚拟列表视。虚拟列表视CListView中列表框风格必须为LVS_OWNERDATA。虚拟列表中数据的填充已经实现,已经达到填充数据所花时间与记录数无关的目的。
现在的问题是,我需要在列表框里实现查找功能,很明显我不能用遍历每行的方式。列表框里每行有5列,我怎么根据其中某项可能的值快速定位出某行?
我知道若风格不为LVS_OWNERDATA,在一个普通列表框里根据第一列(仅限于第一列)的值查找是可以的。例如:
LVFINDINFO info;
info.psz="109";//第一列目标值
info.flags=LVFI_PARTIAL|LVFI_STRING;
int nIndex=GetListCtrl().FindItem(&info);//可以正确得到第一列为"109"的行号
但这里风格不为LVS_OWNERDATA才行,并且只能根据第一列的值查!
是不是需要用到诸如:
LVITEM lparam;
lparam.iSubItem=4;
lparam.mask=LVIF_TEXT;
sprintf(lparam.pszText,strTime);

info.flags=LVFI_PARAM;
info.lParam=lparam;//?这句类型不匹配报错
请高手赐教!分不够只管说。
...全文
245 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
BoXoft 2006-11-04
  • 打赏
  • 举报
回复
根据MSDN的Virtual List Controls一文,显示虚表需要处理LVN_GETDISPINFO通知。处理函数的代码示例如下:
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM* pItem= &(pDispInfo)->item;

int iItemIndx= pItem->iItem;

if (pItem->mask & LVIF_TEXT) //valid text buffer?
{
switch(pItem->iSubItem){
case 0: //fill in main text
lstrcpy(pItem->pszText,
m_Items[iItemIndx].m_strItemText);
break;
case 1: //fill in sub item 1 text
lstrcpy(pItem->pszText,
m_Items[iItemIndx].m_strSubItem1Text);
break;
case 2: //fill in sub item 2 text
lstrcpy(pItem->pszText,
m_Items[iItemIndx].m_strSubItem2Text);
break;
}
}

if pItem->mask & LVIF_IMAGE) //valid image?
pItem->iImage=
m_Items[iItemIndx].m_iImageIndex;

里面的iItemIndx就是虚表行号(从0开始)。明白了这个处理函数,就明白如何查找某项数据了。
Renewal 2006-11-04
  • 打赏
  • 举报
回复
问题已经彻底解决,不需要用数组,因为list的数据与一个记录集绑定,用记录集_RecordsetPtr的Find方法,假设需要查第4个字段(也是列表框里第4列的值)field4="xxx"的所在行号:
//建立索引
pRs->Fields->GetItem("field4")->Properties->GetItem("Optimize")->PutValue("True");
//开始查询
HRESULT hr=pRs->Find("field4= xxx",0,adSearchForward,"");
if(hr==S_OK)
{
_variant_t var=pRs->Bookmark;//得到标签
int iRow=int(var.dblVal);//返回记录集的行号也就是列表框的行号!
}
Renewal 2006-11-04
  • 打赏
  • 举报
回复
OnGetdispinfo()中的调用就现在这个样子应该可以了,可能OnGetdispinfo()中替换成数组显示会更快,但主要是查询。问题是不管用什么,总得先遍历记录集将数据填充到缓冲或数组里,初始化会比较慢。
BoXoft 2006-11-04
  • 打赏
  • 举报
回复
可以做一个Cache类,比如说CXCache,提供一个接口函数[]。实现operator[],用一条select语句就可以。使用时:先 CXCache m_xCache; 再在 OnGetdispinfo()中调用 m_xCache[index]。虽然m_xCache不是结构数组,用法却一样。

Renewal 2006-11-04
  • 打赏
  • 举报
回复
那这样其实还是用的遍历啊。我可直接遍历我的记录集m_pRst,但这样好象很慢。用数据结构保存后查找可能比较快,但填充结构数组可能要花时间。
不知道我说的对不对?
马上要结贴了,分看来全都是你的了。
BoXoft 2006-11-04
  • 打赏
  • 举报
回复
虚表不含实际数据,实际数据是另外保存的,简单的做法是用结构数组,如MSDN例子中的m_Items。例子中的pItem->iItem表示行号(从0开始计数),pItem->iSubItem表示列号(从0开始计数)。
比如现在的虚表可以显示100万行数据,有3列。当拖动垂直滚动条到某个位置时,需要显示第1000列到1100列的数据,就会产生1001条LVN_GETDISPINFO通知。OnGetdispinfo()解析第一条通知,通过pItem->iItem知道现在要显示第1000行的数据,它的第0列文字是m_Items[iItemIndx].m_strItemText,第1列文字是m_Items[iItemIndx].m_strSubItem1Text,第2列文字是m_Items[iItemIndx].m_strSubItem2Text。如果虚表没有图片,就不用考虑pItem->mask & LVIF_IMAGE了。后面的1000条通知同样处理。
快速查找就是针对结构数组m_Items[]的。
以上假定list control是report样式。
Renewal 2006-11-04
  • 打赏
  • 举报
回复
BoXoft() :
这部分代码我程序里有啊,看了你的回帖我还是不知道怎么实现,您就明说吧!我的这部分代码为:
void CTableView::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult)
{
int iIndexs[]=
{
0,4,1,2,3
};

LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
TCHAR szValue[MAX_PATH];

VARIANT varValue;
long index = pDispInfo->item.iItem;
long subItem = pDispInfo->item.iSubItem;
FieldsPtr pFields = m_pRst->Fields;
FieldPtr pField=NULL;
if(pDispInfo->item.mask & LVIF_TEXT)
{
CString strVal;
try
{
m_pRst->PutAbsolutePosition((enum PositionEnum)(index+1));
}
catch(_com_error &e)
{
_bstr_t bstr=e.Description();
return;
}

try
{
varValue=pFields->Item[short(iIndexs[subItem])]->GetValue();
strVal=theApp.Format(varValue);
sprintf(szValue,strVal);
}
catch(_com_error &e)
{
_bstr_t bstr=e.Description();
return;
}
lstrcpyn(pDispInfo->item.pszText, szValue, pDispInfo->item.cchTextMax);//set item text
}

*pResult = 0;
}
CTableView由CListView继承来。m_Items是啥,我用下列代码:
LPSTR df=GetListCtrl().m_Items[0].pszText;
时怎么出现错误:
'm_Items' : is not a member of 'CListCtrl'
'm_Items' 不是CListCtrl的成员变量。
究竟怎么实现快速查找?
Renewal 2006-11-03
  • 打赏
  • 举报
回复
怎么没有人回答啊?

15,976

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧