因为列表框里需要显示的数据多达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;//?这句类型不匹配报错
请高手赐教!分不够只管说。

解决方案 »

  1.   

    根据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开始)。明白了这个处理函数,就明白如何查找某项数据了。
      

  2.   

    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的成员变量。
    究竟怎么实现快速查找?
      

  3.   

    虚表不含实际数据,实际数据是另外保存的,简单的做法是用结构数组,如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样式。
      

  4.   

    那这样其实还是用的遍历啊。我可直接遍历我的记录集m_pRst,但这样好象很慢。用数据结构保存后查找可能比较快,但填充结构数组可能要花时间。
    不知道我说的对不对?
    马上要结贴了,分看来全都是你的了。
      

  5.   

    可以做一个Cache类,比如说CXCache,提供一个接口函数[]。实现operator[],用一条select语句就可以。使用时:先 CXCache m_xCache; 再在 OnGetdispinfo()中调用 m_xCache[index]。虽然m_xCache不是结构数组,用法却一样。
      

  6.   

    OnGetdispinfo()中的调用就现在这个样子应该可以了,可能OnGetdispinfo()中替换成数组显示会更快,但主要是查询。问题是不管用什么,总得先遍历记录集将数据填充到缓冲或数组里,初始化会比较慢。
      

  7.   

    问题已经彻底解决,不需要用数组,因为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->Book;//得到标签
    int iRow=int(var.dblVal);//返回记录集的行号也就是列表框的行号!
    }