青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 298  文章 - 377  trackbacks - 0
<2007年7月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

常用鏈接

留言簿(34)

隨筆分類

隨筆檔案

文章檔案

相冊

收藏夾

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

一般在用CListCtrl顯示大數據量時,都會直接加入到CListCtrl中,這樣會導致界面刷新速度慢,如果有圖片則會導致閃爍。
這是對計算機大數據量處理的思想沒掌握好。
從用戶的角度來考慮,計算機顯示的數據超過一定量后,再增加數據量,用戶不旦不會方便,相反會影響User對有用信息的定位。
所以,用戶界面上始終不應該顯示超大超多的數據。如果數據量很多,則考慮用Filter,Query或分頁顯示。
萬不得一實在要用很多數據,也要將數據先放到內存中,通過GetDispInfo 來顯示用戶想要的數據。而不是將數據都InsertItem中。

1.使用SetRedraw禁止窗口重繪,操作完成后,再恢復窗口重繪
m_ctlList.SetRedraw(FALSE); 
//以下為更新數據操作
//……
//恢復窗口重繪
m_ctlList.SetRedraw(TRUE);
2.使用LockWindowUpdate禁止窗口重繪,操作完成后,用UnlockWindowUpdate恢復窗口重繪
m_ctlList.LockWindowUpdate(); 
//以下為更新數據操作
//……
//恢復窗口重繪
m_ctlList.UnlockWindowUpdate(); 
3.使用ListCtrl的內部雙緩沖
m_ctlLisit.SetExtendedStyle(m_ctlLisit.GetExtendedStyle()|LVS_EX_DOUBLEBUFFER);
VC6未定義LVS_EX_DOUBLEBUFFER宏,使用者可以自定義,如下:
#define LVS_EX_DOUBLEBUFFER 0x00010000
4.Virtual List
首先要設置ListCtrl風格為LVS_REPORT | LVS_OWNERDATA或在ListCtrl屬里中的More Styles頁面中選中Owner data復選框。
其次要向應LVN_GETDISPINFO消息;
void OnGetdispinfoList(NMHDR* pNMHDR, LRESULT* pResult)
{
 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
 LV_ITEM *pItem = &(pDispInfo)->item;
 char szText[128] = {0};
 if (pItem->mask & LVIF_TEXT)
 {
//使緩沖區數據與表格子項對應
//m_ArrayBuff為二維數組
//定義如下 int m_ArrayBuff[2048][4];
  _stprintf(szText,_T("%d"),m_ArrayBuff[pItem->iItem][pItem->iSubItem]);   
  pItem->pszText = szText;  
 } 
 *pResult = 0;
}
最后便是生成緩沖區數據
void Insertdata()
{
 //刪除之前的數據
 m_ctlList.SetItemCountEx(0);
 m_ctlList.Invalidate();
    m_ctlList.UpdateWindow();
 srand( (unsigned)time( NULL ));
 
 //生成新的數據緩沖區
 int nItemCount = 2048;
 for (int i = 0;i < nItemCount; i ++)
 {
  for (int k = 0;k < 4;k ++)
  {
   m_ArrayBuff[i][k] = rand()%2048 + 1;
  }
 }
 if (nItemCount < 2)    
  m_ctlList.SetItemCountEx(1);   
 else
  m_ctlList.SetItemCountEx(nItemCount);
 m_ctlList.Invalidate();
若要修改數據,只要修改緩沖區m_ArrayBuff的數據即可以
5.Custom Redraw
既然是自繪,首先當然是重載CListCtrl類,并接管WM_ERASEBKGND消息,去掉默認的處理,改為不處理
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
{
//響應WM_ERASEBKGND消息 
 return false;
 //屏蔽默認處理
 //return CListCtrl::OnEraseBkgnd(pDC);
}
void CListCtrlEx::OnPaint()
{
    //響應WM_PAINT消息
    CPaintDC dc(this); // device context for painting
    CRect rect;
    CRect headerRect;
    CDC MenDC;//內存ID表  
    CBitmap MemMap;
    GetClientRect(&rect);   
    GetDlgItem(0)->GetWindowRect(&headerRect);  
    MenDC.CreateCompatibleDC(&dc);  
    MemMap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
    MenDC.SelectObject(&MemMap);
    MenDC.FillSolidRect(&rect,#e4ecf3);  
    //這一句是調用默認的OnPaint(),把圖形畫在內存DC表上  
    DefWindowProc(WM_PAINT,(WPARAM)MenDC.m_hDC,(LPARAM)0);      
    //輸出  
    dc.BitBlt(0,headerRect.Height(),rect.Width(),  rect.Height(),&MenDC,0, headerRect.Height(),SRCCOPY);  
    MenDC.DeleteDC();
    MemMap.DeleteObject();
}

// BMPListDlg.cpp : implementation file
//

#include 
"stdafx.h"
#include 
"BMPList.h"
#include 
"BMPListDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
    CAboutDlg();

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    
protected:
    
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CBMPListDlg dialog


CBMPListDlg::CBMPListDlg(CWnd
* pParent /*=NULL*/)
    : CDialog(CBMPListDlg::IDD, pParent)
{
    m_hIcon 
= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CBMPListDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST1, m_cList);
}

BEGIN_MESSAGE_MAP(CBMPListDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST1, GetDispInfo)
    
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CBMPListDlg message handlers

BOOL CBMPListDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    
// Add "About" menu item to system menu.

    
// IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0== IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX 
< 0xF000);

    CMenu
* pSysMenu = GetSystemMenu(FALSE);
    
if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        
if (!strAboutMenu.IsEmpty())
        {
            pSysMenu
->AppendMenu(MF_SEPARATOR);
            pSysMenu
->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    
// Set the icon for this dialog.  The framework does this automatically
    
// when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    
// Create 256 color image lists
    
// Need to create image list with a phantom bitmap.
    
// This image list is only used to hold the place.  The images are loaded
    
// dynamically as the list control is scrolled.
    if(m_imageList.GetSafeHandle() == NULL)
    {
        m_imageList.Create(
210160, ILC_COLOR24 | ILC_MASK, 81);
        m_cList.SetImageList(
&m_imageList, LVSIL_SMALL);
        m_cList.SetImageList(
&m_imageList, LVSIL_NORMAL);
        m_imageList.SetImageCount(
1);
    }

    
// Set up list control
    
// Nothing special here.  Just some columns for the report view.
    m_cList.InsertColumn(0, _T("Column 1"), LVCFMT_LEFT, 200);
    m_cList.InsertColumn(
1, _T("Column 2"), LVCFMT_LEFT, 100);
    m_cList.InsertColumn(
3, _T("Column 3"), LVCFMT_LEFT, 100);
    m_cList.InsertColumn(
4, _T("Column 4"), LVCFMT_LEFT, 100);
    m_cList.SetExtendedStyle(LVS_EX_FULLROWSELECT 
|LVS_EX_INFOTIP | LVS_EX_FLATSB |LVS_EX_GRIDLINES);

    
// Add some data
    InsertItems();
    
return TRUE;  // return TRUE  unless you set the focus to a control
}

void CBMPListDlg::GetDispInfo(NMHDR *pNMHDR, LRESULT *pResult)
{
    NMLVDISPINFO 
*pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);

    
//Create a pointer to the item
    LV_ITEM* pItem= &(pDispInfo)->item;

    
//Which item number?
    int nItem = pItem->iItem;

    CMyDataInfo 
*pInfo = NULL;
    
if(nItem > m_MyDataArray.GetSize()-1)
        
return// Just to be safe

    pInfo 
= (CMyDataInfo *)m_MyDataArray.GetAt(nItem);
    
if(pInfo == NULL)
        
return;
    
    
//Do we need text information?
    if (pItem->mask & LVIF_TEXT) {
        CString csText;

        
//Which column?
        if(pItem->iSubItem == 0)
            csText 
= pInfo->m_csColumn1;
        
else if (pItem->iSubItem == 1// Column 1
            csText = pInfo->m_csColumn2;
        
else if (pItem->iSubItem == 2// Column 2
            csText = pInfo->m_csColumn3;
        
else if (pItem->iSubItem == 3// Column 3
            csText = pInfo->m_csColumn4;

        
//Copy the text to the LV_ITEM structure
        
//Maximum number of characters is in pItem->cchTextMax
        lstrcpyn(pItem->pszText, csText, pItem->cchTextMax);
    }

    
//Does the list need image information?
    if( pItem->mask & LVIF_IMAGE) {
        TRACE(_T(
"pItem|%d|%d\n"), pItem->iItem, pItem->iSubItem);
        
// Need to reset first item of image list to the correct bitmap
        HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),pInfo->m_csImage,
            IMAGE_BITMAP,
0,0,LR_LOADFROMFILE);
        
if(hBmp != NULL) {
            CBitmap 
*cBmp = CBitmap::FromHandle(hBmp);
            
if(cBmp != NULL)
                m_imageList.Replace(
0,cBmp,NULL);
        }
        
// Note, there is no Navigator 0.bmp so that image will always display blank to 
        
// illustrate what would happen when the file is not found.
        else {
            CBitmap 
*cBmp = new CBitmap();
            cBmp
->LoadBitmap(IDB_BLANK);
            m_imageList.Replace(
0,cBmp,NULL);
            delete cBmp;
        }
        pItem
->iImage = 0// Always use 0 since only one element
    }
    
*pResult = 0;
}

void CBMPListDlg::InsertItems()
{
    m_MyDataArray.RemoveAll(); 
// Clear the array

    
// Add some data (100000 records)
    
// These items are stored in an array, not in the list control itself.
    
// We're just putting in enough here to identify the row and column
    
// This is the slowest operation in the prgram, but we need some data
    
// to do the illustration.
    for(int i = 0; i < 100++i) {
        CMyDataInfo 
*pInfo = new CMyDataInfo();
        
if(pInfo) {
            CString cs;
            cs.Format(_T(
"R%dColumn1"),i);
            pInfo
->m_csColumn1 = cs;
            cs.Format(_T(
"R%dColumn2"),i);
            pInfo
->m_csColumn2 = cs;
            cs.Format(_T(
"R%dColumn3"),i);
            pInfo
->m_csColumn3 = cs;
            cs.Format(_T(
"R%dColumn4"),i);
            pInfo
->m_csColumn4 = cs;

            
// This will count from Navigator 0.bmp to Navigator 4.bmp.  There is no
            
// file Navigator 0.bmp so those rows will use the blank bitmap from the build in
            
// resources.
            cs.Format(_T("Navigator %d.bmp"),(i % 5));
            pInfo
->m_csImage = cs; // Just repeat images every 4 
            m_MyDataArray.Add(pInfo);
        }
    }

    m_cList.DeleteAllItems();

    
// This sets the count in the list without adding any items.  This is very fast.
    m_cList.SetItemCountEx((int)m_MyDataArray.GetCount(), LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
}

void CBMPListDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    
if ((nID & 0xFFF0== IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    
else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CBMPListDlg::OnPaint()
{
    
if (IsIconic())
    {
        CPaintDC dc(
this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast
<WPARAM>(dc.GetSafeHdc()), 0);

        
// Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        
int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(
&rect);
        
int x = (rect.Width() - cxIcon + 1/ 2;
        
int y = (rect.Height() - cyIcon + 1/ 2;

        
// Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    
else
    {
        CDialog::OnPaint();
    }
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CBMPListDlg::OnQueryDragIcon()
{
    
return static_cast<HCURSOR>(m_hIcon);
}





// BMPListDlg.h : header file
//

#pragma once
#include 
"afxcmn.h"

// Data object handling class
class CMyDataInfo : public CObject
{
// Construction/Destruction
public:
    CMyDataInfo() {};
    
~CMyDataInfo() {};
// Attributes
public:
    CString m_csColumn1;
    CString m_csColumn2;
    CString m_csColumn3;
    CString m_csColumn4;
    CString m_csImage; 
// BMP to show

// Implementation
};

class CMyDataArray : public CObArray
{
// Construction/Destruction
public:
    CMyDataArray() {};
    
~CMyDataArray() {
        
for(int i = 0; i < GetSize(); ++ i)
            delete GetAt(i);
        RemoveAll();
    };

// Attributes
public:
};

// CBMPListDlg dialog
class CBMPListDlg : public CDialog
{
// Construction
public:
    CBMPListDlg(CWnd
* pParent = NULL);    // standard constructor
    ~CBMPListDlg(){m_imageList.DeleteImageList();};
    
// Dialog Data
    enum { IDD = IDD_BMPLIST_DIALOG };

    
protected:
    
virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support


// Implementation
protected:
    HICON m_hIcon;
    CImageList    m_imageList;
    
void InsertItems();
    
int m_nItems;
    CMyDataArray m_MyDataArray;
    
    
// Generated message map functions
    virtual BOOL OnInitDialog();
    afx_msg 
void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg 
void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg 
void GetDispInfo(NMHDR *pNMHDR, LRESULT *pResult);
    DECLARE_MESSAGE_MAP()
public:
    CListCtrl m_cList;
};

posted on 2013-04-25 20:13 聶文龍 閱讀(3940) 評論(1)  編輯 收藏 引用

FeedBack:
# re: CLISTCTRL 顯示圖片及大批量數據的加載速度與閃爍問題 2013-04-25 20:39 聶文龍
clistctrl 虛擬列表
一、什么是虛擬列表控件
虛擬列表控件是指帶有LVS_OWNERDATA風格的列表控件。。

二、為什么使用虛擬列表控件

我們知道,通常使用列表控件CListCtrl,需要調用InsertItem把要顯示的數據插入列表中,之后我們就不必關心數據在哪里了,這是因為控件自己開辟了內存空間來保存這些數據。現在假設我們要顯示一個數據庫,里面的信息量很大,有幾十萬條記錄。通常有兩種方法解決這個問題:1是僅僅在ListCtrl中插入少量的數據,比如100個,然后通過[上一頁][下一頁]兩個按鈕進行控制,某一時刻顯示的只是從xxx到xxx+100之間的記錄。2是把所有數據全部插入到ListCtrl中,然后讓用戶通過滾動來查看數據。無疑,很多用戶喜歡采用第二種方式,特別是對于已經排序的數據,用戶只需用鍵盤輸入某行的開頭字符,就可以快速定位到某一行。但是,如果這樣做,InsertItem插入數據的過程將是很漫長的,而且用戶會看到ListCtrl刷新速度也很慢,而且所有數據都位于內存中消耗了大量的內存,當數據多達上萬以后幾乎是不能忍受的。

為此,mfc特別提供了虛擬列表的支持。一個虛擬列表看起來和普通的ListCtrl一樣,但是不用通過InsertItem來插入數據,它僅僅知道自己應該顯示多少數據。但是它如何知道要顯示什么數據呢?秘密就在于當列表控件需要顯示某個數據的時候,它向父窗口要。假設這個列表控件包含100個元素,第10到20個元素(行)是可見的。當列表控件重畫的時候 ,它首先請求父窗口給它第10個元素的數據,父窗口收到請求以后,把數據信息填充到列表提供的一個結構中,列表就可以用來顯示了,顯示第10個數據后,列表會繼續請求下一個數據。

在虛擬的樣式下,ListCtrl可以支持多達DWORD個數據項。(缺省的listctrl控件最多支持int個數據項)。但是,虛擬列表的最大優點不在于此,而是它僅僅需要在內存中保持極少量的數據,從而加快了顯示的速度。所以,在使用列表控件顯示一個很大的數據庫的情況下,采用虛擬列表最好不過了。

不僅CListCtrl提供虛擬列表的功能, MFC的CListView類也有同樣的功能。

三、虛擬列表控件的消息


虛擬列表總共發送三個消息給父窗口:當它需要數據的時候,它發送LVN_GETDISPINFO消息。這是最重要的消息。當用戶試圖查找某個元素的時候,它發送LVN_ODFINDITEM消息;還有一個消息是LVN_ODCACHEHINT,用來緩沖數據,基本上很少用到這個消息。

虛擬列表控件使用起來非常簡單。它總共只有三個相關的消息,如果你直接使用CListCtrl,應該在對話框中響應這三個消息。如果你使用CListCtrl派生類,可以在派生類中響應這三個消息的反射消息。這三個消息分別是:

(1)LVN_GETDISPINFO 控件請求某個數據
(2)LVN_ODFINDITEM 查找某個數據
(3)LVN_ODCACHEHINT 緩沖某一部分數據

我們必須響應的消息是(1),多數情況下要響應(2),極少數的情況下需要響應(3)

四、如何使用虛擬列表控件

1、首先要創建控件,創建一個虛擬列表和創建一個正常的 CListCtrl差不多。先在資源編輯器里面添加一個list control資源。然后選中"Owner data"屬性,然后給它捆綁一個CListCtrl變量。添加列,添加imagelist等都和使用正常的listctrl一樣。

2、給虛擬列表添加元素。假設 m_list 是這個列表的控制變量。通常的情況下這樣添加數據:

m_list.InsertItem(0, _T("Hello world"));

但是對于虛擬列表,不能這么做。只需告訴列表有多少個數據:

//總共顯示100行
m_list.SetItemCount(100);

3、處理它的通知消息。

五、如何響應虛擬列表的消息

1、處理 LVN_GETDISPINFO 通知消息

當虛擬列表控件需要某個數據的時候,它給父窗口發送一個 LVN_GETDISPINFO通知消息,表示請求某個數據。因此列表的所有者窗口(或者它自己)必須處理這個消息。例如派生類的情況 (CMyListCtrl是一個虛擬列表類對象):

//這里處理的是反射消息
BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CMyListCtrl)
ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

在LVN_GETDISPINFO的處理函數中,必須首先檢查列表請求的是什么數據,可能的值包括:

(1)LVIF_TEXT 必須填充 pszText
(2)LVIF_IMAGE 必須填充 iImage
(3)LVIF_INDENT 必須填充 iIndent
(4)LVIF_PARAM 必須填充 lParam
(5)LVIF_STATE 必須填充 state

根據它的請求,填充所需的數據即可。

//================= 例子代碼=====================================

下面的給出一個例子,填充的是列表所需的某個數據項的文字以及圖像信息:

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

int iItemIndx= pItem->iItem;

if (pItem->mask & LVIF_TEXT) //字符串緩沖區有效
{
switch(pItem->iSubItem){
case 0: //填充數據項的名字
lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strItemText);
break;
case 1: //填充子項1
lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strSubItem1Text);
break;
case 2: //填充子項2
lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strSubItem2Text);
break;
}
}
/*注意,多數情況下要使用lstrcpyn ,因為最多復制字符的個數由pItem->cchTextMax給出:
lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
*/

if (pItem->mask & LVIF_IMAGE) //是否請求圖像
pItem->iImage= m_Items[iItemIndx].m_iImageIndex;

甚至連某行數據是否選中(當有checkbox的情況下)的信息也需要由用戶自己來維護,例如:
//是否顯示該行的選擇信息?
if(IsCheckBoxesVisible()) //自定義函數
{
pItem->mask |= LVIF_STATE;
pItem->stateMask = LVIS_STATEIMAGEMASK;

if(m_database[itemid].m_checked)
{
pItem->state = INDEXTOSTATEIMAGEMASK(2);
}
else
{
pItem->state = INDEXTOSTATEIMAGEMASK(1);
}
}


2、處理 LVN_ODFINDITEM 消息

在資源管理器里面,定位到某個文件夾,會顯示很多文件,如果按下鍵盤的‘A’,則資源管理器會自動找到名字以 'A'打頭的文件夾或者文件, 并選擇該文件。繼續按 A,如果還有其它名字以'A'打頭的文件,則下一個文件被選中。如果輸入 "AB",則 'AB'打頭的文件被選中。這就是列表控件的自動查找功能。

當虛擬列表收到一個LVM_FINDITEM消息,它也會發送這個消息通知父窗口查找目標元素。要搜索的信息通過 LVFINDINFO 結構給出。它是 NMLVFINDITEM 結構的一個成員。當找到要搜索的數據后,應該把該數據的索引(行號)返回,如果沒有找到,則返回-1。

以對話框為例,響應函數大致如下:

//================= 例子代碼=====================================
void CVirtualListDlg::OnOdfinditemList(NMHDR* pNMHDR, LRESULT* pResult)
{
// pNMHDR 里面是要查找的元素的信息
// 要選中的目標元素的行號最后要保存在 pResult 中, 這是關鍵!

NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR;

/* pFindInfo->iStart 是查找的起始位置,一直到最后,然后從頭開始,如果沒有找到合適的,最終停留在iStart*/

*pResult = -1;

//是否按照文字查找?
if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
{
return;
}

//這是我們要找的字符串
CString searchstr = pFindInfo->lvfi.psz;

int startPos = pFindInfo->iStart;//保存起始位置

//判斷是否最后一行
if(startPos >= m_list.GetItemCount())
startPos = 0;

int currentPos=startPos;

//開始查找
do
{
if( _tcsnicmp(m_database[currentPos].m_name,
searchstr, searchstr.GetLength()) == 0)
{
//選中這個元素,停止查找
*pResult = currentPos;
break;
}

currentPos++;

//從頭開始
if(currentPos >= m_list.GetItemCount())
currentPos = 0;

}while(currentPos != startPos);
}

顯然,如果數據很多,必須實現一個快速查找的方法。

關于pFindInfo->lvfi里面的信息的詳細說明可以參考 MSDN。

3、處理 LVN_ODCACHEHINT 消息。

假如我們從數據庫或者其它地方讀取數據的速度比較慢,則可以利用這個消息,批量讀取一些數據,然后根據請求,逐個提供給虛擬列表。LVN_ODCACHEHINT消息的用途就是給程序一個緩沖數據的機會。以提高程序的性能。

//================= 例子代碼=====================================
使用 ClassWizard 重載 OnChildNotify 函數,檢查是否 LVN_ODCACHEHINT 消息,然后準備緩沖數據:

NMLVCACHEHINT* pcachehint=NULL;

NMHDR* phdr = (NMHDR*)lParam;

if(phdr->code == LVN_ODCACHEHINT)
{
pcachehint= (NMLVCACHEHINT*) phdr;
//自定義函數,準備指定范圍的數據到緩沖區
PrepCache(pcachehint->iFrom, pcachehint->iTo);
}
else ...

注意,如果消息不是 LVN_ODCACHEHINT,則要傳遞給基類進行處理。

五、如何修改ListCtrl顯示的數據。

由于是程序自己維護數據,所以只需修改數據庫中的數據,然后調用CListCtrl::RedrawItems函數進行重畫即可。

六、數據的選擇狀態和選擇框

CListCtrl可以顯示checkbox選擇框。有些情況下是很有用的。對于正常的listctrl,用戶可以用鼠標來修改某個元素的選擇狀態,但是對于虛擬列表就不行了。必須自己處理一些消息,然后自己保存數據的選中狀態:

void CVirtualListDlg::ToggleCheckBox(int item)
{
m_database[item].m_checked = !m_database[item].m_checked;
m_list.RedrawItems(item, item);
}

處理 LVN_KEYDOWN消息,添加對空格鍵 的響應,用于切換選擇狀態:

void CVirtualListDlg::OnKeydownList(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR;

if( pLVKeyDown->wVKey == VK_SPACE )
{
int item = m_list.GetSelectionMark();
if(item != -1)
ToggleCheckBox(item);
}

*pResult = 0;
}

然后處理 NM_CLICK 消息:

void CVirtualListDlg::OnClickList(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

LVHITTESTINFO hitinfo;
hitinfo.pt = pNMListView->ptAction;

int item = m_list.HitTest(&hitinfo);

if(item != -1)
{
//看看鼠標是否單擊在 check box上面了?
if( (hitinfo.flags & LVHT_ONITEMSTATEICON) != 0)
{
ToggleCheckBox(item);
}
}

*pResult = 0;
}

七、備注:

1、虛擬列表無法進行排序。

2、虛表的一個優點是容易保持和數據庫的同步。修改數據庫中的數據,然后重畫list十分容易而且高效。

3、虛表的另一個優點是可以根據需要產生數據。比如在某一列加上行號。

http://blog.vckbase.com/iwaswzq/archive/2006/07/07/21113.html
http://www.codeproject.com/KB/list/virtuallist.aspx  回復  更多評論
  

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
      <noscript id="pjuwb"></noscript>
            <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
              <dd id="pjuwb"></dd>
              <abbr id="pjuwb"></abbr>
              久久综合狠狠综合久久综青草| 国产亚洲欧美一级| 亚洲免费成人av电影| 欧美成人精品福利| 欧美激情一区在线| 久久久水蜜桃av免费网站| 亚洲七七久久综合桃花剧情介绍| 在线成人www免费观看视频| 亚洲人成毛片在线播放女女| 国产精品videosex极品| 午夜精品久久久久久久| 亚洲精品在线免费| 欧美激情一区二区三级高清视频| 性色一区二区三区| 亚洲欧美成人综合| 久久综合九色欧美综合狠狠| 欧美区一区二区三区| 欧美精品亚洲精品| 欧美视频网址| 极品av少妇一区二区| 亚洲蜜桃精久久久久久久| 亚洲欧美国产视频| 欧美电影免费观看高清| 亚洲小说欧美另类婷婷| 另类av导航| 国产欧美日韩免费看aⅴ视频| 亚洲国产精品第一区二区| 亚洲欧美成人一区二区在线电影| 蜜臀av性久久久久蜜臀aⅴ四虎 | 国产精品国产亚洲精品看不卡15| 国产精品一区二区久久久久| 影音先锋日韩精品| 亚洲网友自拍| 欧美黄在线观看| 亚洲自拍16p| 欧美黄免费看| 韩国欧美一区| 欧美一区二区三区的| 欧美激情无毛| 精品动漫3d一区二区三区免费| 在线一区亚洲| 99re8这里有精品热视频免费| 久久国产夜色精品鲁鲁99| 91久久极品少妇xxxxⅹ软件| 中文有码久久| 欧美韩日一区二区三区| 伊人久久婷婷色综合98网| 午夜精品福利在线| 99在线热播精品免费| 欧美成人国产一区二区 | 中文一区字幕| 亚洲风情在线资源站| 久久久www成人免费毛片麻豆| 一区二区三区蜜桃网| 久久久夜精品| 国产亚洲欧洲一区高清在线观看| 亚洲性夜色噜噜噜7777| 亚洲精品免费一区二区三区| 免费观看日韩| 在线观看视频欧美| 男女av一区三区二区色多| 久久福利资源站| 国产精品自在在线| 欧美一区二区日韩| 亚洲欧美日本精品| 一本色道久久综合亚洲91| 欧美激情免费观看| 99re8这里有精品热视频免费 | 国产欧美亚洲日本| 香蕉免费一区二区三区在线观看| 亚洲丰满在线| 免费亚洲网站| 美女黄网久久| 亚洲另类视频| 欧美成人在线网站| 欧美成人69av| 宅男在线国产精品| 一区二区三区不卡视频在线观看 | 久久精品在这里| 在线播放中文字幕一区| 欧美激情国产日韩| 欧美日韩国产不卡在线看| 亚洲一二三区在线| 午夜一级在线看亚洲| 伊人伊人伊人久久| 亚洲人成网站在线播| 国产精品久久久久999| 久久久蜜臀国产一区二区| 麻豆国产精品一区二区三区 | 麻豆国产精品一区二区三区| 日韩系列在线| 亚洲激情在线| 亚洲午夜精品一区二区| 狠狠色狠狠色综合日日五| 亚洲国产精品999| 欧美午夜精品一区| 久久精品国产综合精品| 麻豆av一区二区三区| 亚洲欧美美女| 久久久噜噜噜久久久| 9国产精品视频| 久久av一区二区三区| 99re66热这里只有精品4| 久久爱91午夜羞羞| 亚洲视频中文字幕| 久久一二三区| 亚洲欧美日韩一区| 欧美激情第3页| 久久精品男女| 在线亚洲+欧美+日本专区| 国产农村妇女毛片精品久久莱园子| 美女999久久久精品视频| 欧美日韩成人在线| 免费在线欧美视频| 国产精品乱人伦一区二区| 欧美高清在线观看| 国产欧美日韩一级| 一区二区三区日韩精品| 亚洲精品视频在线播放| 欧美专区在线观看| 欧美一区国产一区| 国产精品久久久久久户外露出| 亚洲高清在线播放| 亚洲国产精品国自产拍av秋霞| 香蕉乱码成人久久天堂爱免费| 亚洲一区二区在线播放| 欧美寡妇偷汉性猛交| 欧美成年视频| 在线观看亚洲| 久久久久久久网站| 久热国产精品| 激情自拍一区| 久久精品免费看| 久久亚洲综合色| 国产专区一区| 久久激情五月激情| 久久精品国产久精国产思思| 国产欧美精品日韩区二区麻豆天美| 一本综合精品| 亚洲欧美日韩国产成人精品影院| 欧美日韩一区二区三区在线 | 亚洲国产精品www| 91久久精品国产| 欧美精品免费在线观看| 亚洲日本视频| 亚洲一区二区精品在线| 欧美视频精品在线| 99av国产精品欲麻豆| 亚洲免费人成在线视频观看| 国产精品99免费看| 亚洲一区在线免费| 久久狠狠婷婷| **网站欧美大片在线观看| 久久夜精品va视频免费观看| 亚洲电影在线| 亚洲一区二区影院| 国产日韩精品一区二区三区| 欧美在线观看视频一区二区三区 | 亚洲一级在线观看| 欧美中日韩免费视频| 国产综合色一区二区三区| 久久国产精彩视频| 亚洲大片精品永久免费| 一本久久a久久免费精品不卡| 国产精品成人在线| 欧美制服丝袜第一页| 亚洲丰满少妇videoshd| 亚洲欧美中文另类| 狠狠色狠狠色综合人人| 亚洲电影自拍| 亚洲摸下面视频| 一区二区在线不卡| 欧美色欧美亚洲高清在线视频| 亚欧美中日韩视频| 亚洲欧洲日夜超级视频| 欧美一区二区三区日韩视频| 在线免费观看日韩欧美| 亚洲男人影院| 免费91麻豆精品国产自产在线观看| 亚洲日本理论电影| 国产日韩欧美一区| 欧美精品日韩一区| 久久成人一区| 亚洲精品美女久久久久| 久久精品官网| 亚洲香蕉伊综合在人在线视看| 激情综合色综合久久| 欧美精品福利视频| 欧美一区二区三区四区夜夜大片 | 一区二区三区 在线观看视| 国产精品人人做人人爽人人添| 久久夜色精品国产噜噜av| 亚洲欧美日韩一区在线| 在线免费观看视频一区| 国产精品视频xxxx| 欧美偷拍另类| 欧美二区乱c少妇| 欧美中文日韩| 亚洲欧美日韩在线播放| 一本大道av伊人久久综合|