• <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>
            隨筆 - 298  文章 - 377  trackbacks - 0
            <2013年4月>
            31123456
            78910111213
            14151617181920
            21222324252627
            2829301234
            567891011

            常用鏈接

            留言簿(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 聶文龍 閱讀(3872) 評論(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  回復  更多評論
              
            国产亚洲欧美精品久久久| 久久精品这里只有精99品| 伊人久久免费视频| 99久久伊人精品综合观看| 91麻精品国产91久久久久| 欧美大香线蕉线伊人久久| 国内精品人妻无码久久久影院| 久久亚洲sm情趣捆绑调教| 亚洲日本va中文字幕久久| 久久精品国产清高在天天线| 久久久久夜夜夜精品国产| 久久久久久国产精品免费免费 | 国产精品丝袜久久久久久不卡| 日本一区精品久久久久影院| 国内精品伊人久久久久网站| 久久无码国产专区精品| 久久婷婷国产剧情内射白浆 | 亚洲精品成人久久久| 久久久久se色偷偷亚洲精品av| 亚洲国产综合久久天堂| 精产国品久久一二三产区区别| 日韩人妻无码一区二区三区久久| 久久精品蜜芽亚洲国产AV| 久久99精品国产99久久| 777午夜精品久久av蜜臀| 久久精品国产亚洲av影院| 国产精品嫩草影院久久| 精品久久久久久中文字幕大豆网| 久久99精品久久久久久久不卡| 国产免费福利体检区久久| 国产亚洲精品久久久久秋霞 | 亚洲精品乱码久久久久久中文字幕| 国产成人精品久久亚洲高清不卡| 青青草国产97免久久费观看| 久久精品国产精品国产精品污| 欧美亚洲另类久久综合婷婷| 久久亚洲欧美国产精品| 狠狠久久综合| 国产日产久久高清欧美一区| 日韩精品久久久久久久电影| 国产69精品久久久久APP下载|