• <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
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

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

            1.使用SetRedraw禁止窗口重繪,操作完成后,再恢復(fù)窗口重繪
            m_ctlList.SetRedraw(FALSE); 
            //以下為更新數(shù)據(jù)操作
            //……
            //恢復(fù)窗口重繪
            m_ctlList.SetRedraw(TRUE);
            2.使用LockWindowUpdate禁止窗口重繪,操作完成后,用UnlockWindowUpdate恢復(fù)窗口重繪
            m_ctlList.LockWindowUpdate(); 
            //以下為更新數(shù)據(jù)操作
            //……
            //恢復(fù)窗口重繪
            m_ctlList.UnlockWindowUpdate(); 
            3.使用ListCtrl的內(nèi)部雙緩沖
            m_ctlLisit.SetExtendedStyle(m_ctlLisit.GetExtendedStyle()|LVS_EX_DOUBLEBUFFER);
            VC6未定義LVS_EX_DOUBLEBUFFER宏,使用者可以自定義,如下:
            #define LVS_EX_DOUBLEBUFFER 0x00010000
            4.Virtual List
            首先要設(shè)置ListCtrl風(fēng)格為LVS_REPORT | LVS_OWNERDATA或在ListCtrl屬里中的More Styles頁面中選中Owner data復(fù)選框。
            其次要向應(yīng)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)
             {
            //使緩沖區(qū)數(shù)據(jù)與表格子項(xiàng)對(duì)應(yīng)
            //m_ArrayBuff為二維數(shù)組
            //定義如下 int m_ArrayBuff[2048][4];
              _stprintf(szText,_T("%d"),m_ArrayBuff[pItem->iItem][pItem->iSubItem]);   
              pItem->pszText = szText;  
             } 
             *pResult = 0;
            }
            最后便是生成緩沖區(qū)數(shù)據(jù)
            void Insertdata()
            {
             //刪除之前的數(shù)據(jù)
             m_ctlList.SetItemCountEx(0);
             m_ctlList.Invalidate();
                m_ctlList.UpdateWindow();
             srand( (unsigned)time( NULL ));
             
             //生成新的數(shù)據(jù)緩沖區(qū)
             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();
            若要修改數(shù)據(jù),只要修改緩沖區(qū)m_ArrayBuff的數(shù)據(jù)即可以
            5.Custom Redraw
            既然是自繪,首先當(dāng)然是重載CListCtrl類,并接管WM_ERASEBKGND消息,去掉默認(rèn)的處理,改為不處理
            BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
            {
            //響應(yīng)WM_ERASEBKGND消息 
             return false;
             //屏蔽默認(rèn)處理
             //return CListCtrl::OnEraseBkgnd(pDC);
            }
            void CListCtrlEx::OnPaint()
            {
                //響應(yīng)WM_PAINT消息
                CPaintDC dc(this); // device context for painting
                CRect rect;
                CRect headerRect;
                CDC MenDC;//內(nèi)存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);  
                //這一句是調(diào)用默認(rèn)的OnPaint(),把圖形畫在內(nèi)存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) 評(píng)論(1)  編輯 收藏 引用

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

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

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

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

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

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

            三、虛擬列表控件的消息


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

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

            (1)LVN_GETDISPINFO 控件請(qǐng)求某個(gè)數(shù)據(jù)
            (2)LVN_ODFINDITEM 查找某個(gè)數(shù)據(jù)
            (3)LVN_ODCACHEHINT 緩沖某一部分?jǐn)?shù)據(jù)

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

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

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

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

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

            但是對(duì)于虛擬列表,不能這么做。只需告訴列表有多少個(gè)數(shù)據(jù):

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

            3、處理它的通知消息。

            五、如何響應(yīng)虛擬列表的消息

            1、處理 LVN_GETDISPINFO 通知消息

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

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

            在LVN_GETDISPINFO的處理函數(shù)中,必須首先檢查列表請(qǐng)求的是什么數(shù)據(jù),可能的值包括:

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

            根據(jù)它的請(qǐng)求,填充所需的數(shù)據(jù)即可。

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

            下面的給出一個(gè)例子,填充的是列表所需的某個(gè)數(shù)據(jù)項(xiàng)的文字以及圖像信息:

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

            int iItemIndx= pItem->iItem;

            if (pItem->mask & LVIF_TEXT) //字符串緩沖區(qū)有效
            {
            switch(pItem->iSubItem){
            case 0: //填充數(shù)據(jù)項(xiàng)的名字
            lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strItemText);
            break;
            case 1: //填充子項(xiàng)1
            lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strSubItem1Text);
            break;
            case 2: //填充子項(xiàng)2
            lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strSubItem2Text);
            break;
            }
            }
            /*注意,多數(shù)情況下要使用lstrcpyn ,因?yàn)樽疃鄰?fù)制字符的個(gè)數(shù)由pItem->cchTextMax給出:
            lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
            */

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

            甚至連某行數(shù)據(jù)是否選中(當(dāng)有checkbox的情況下)的信息也需要由用戶自己來維護(hù),例如:
            //是否顯示該行的選擇信息?
            if(IsCheckBoxesVisible()) //自定義函數(shù)
            {
            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 消息

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

            當(dāng)虛擬列表收到一個(gè)LVM_FINDITEM消息,它也會(huì)發(fā)送這個(gè)消息通知父窗口查找目標(biāo)元素。要搜索的信息通過 LVFINDINFO 結(jié)構(gòu)給出。它是 NMLVFINDITEM 結(jié)構(gòu)的一個(gè)成員。當(dāng)找到要搜索的數(shù)據(jù)后,應(yīng)該把該數(shù)據(jù)的索引(行號(hào))返回,如果沒有找到,則返回-1。

            以對(duì)話框?yàn)槔憫?yīng)函數(shù)大致如下:

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

            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)
            {
            //選中這個(gè)元素,停止查找
            *pResult = currentPos;
            break;
            }

            currentPos++;

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

            }while(currentPos != startPos);
            }

            顯然,如果數(shù)據(jù)很多,必須實(shí)現(xiàn)一個(gè)快速查找的方法。

            關(guān)于pFindInfo->lvfi里面的信息的詳細(xì)說明可以參考 MSDN。

            3、處理 LVN_ODCACHEHINT 消息。

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

            //================= 例子代碼=====================================
            使用 ClassWizard 重載 OnChildNotify 函數(shù),檢查是否 LVN_ODCACHEHINT 消息,然后準(zhǔn)備緩沖數(shù)據(jù):

            NMLVCACHEHINT* pcachehint=NULL;

            NMHDR* phdr = (NMHDR*)lParam;

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

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

            五、如何修改ListCtrl顯示的數(shù)據(jù)。

            由于是程序自己維護(hù)數(shù)據(jù),所以只需修改數(shù)據(jù)庫中的數(shù)據(jù),然后調(diào)用CListCtrl::RedrawItems函數(shù)進(jìn)行重畫即可。

            六、數(shù)據(jù)的選擇狀態(tài)和選擇框

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

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

            處理 LVN_KEYDOWN消息,添加對(duì)空格鍵 的響應(yīng),用于切換選擇狀態(tài):

            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)
            {
            //看看鼠標(biāo)是否單擊在 check box上面了?
            if( (hitinfo.flags & LVHT_ONITEMSTATEICON) != 0)
            {
            ToggleCheckBox(item);
            }
            }

            *pResult = 0;
            }

            七、備注:

            1、虛擬列表無法進(jìn)行排序。

            2、虛表的一個(gè)優(yōu)點(diǎn)是容易保持和數(shù)據(jù)庫的同步。修改數(shù)據(jù)庫中的數(shù)據(jù),然后重畫list十分容易而且高效。

            3、虛表的另一個(gè)優(yōu)點(diǎn)是可以根據(jù)需要產(chǎn)生數(shù)據(jù)。比如在某一列加上行號(hào)。

            http://blog.vckbase.com/iwaswzq/archive/2006/07/07/21113.html
            http://www.codeproject.com/KB/list/virtuallist.aspx  回復(fù)  更多評(píng)論
              

            只有注冊用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            国内精品久久久久影院日本| 久久久久久曰本AV免费免费| 国产精品久久久久影视不卡| 97久久精品无码一区二区天美| 久久亚洲国产精品一区二区| 精品久久久久久无码人妻蜜桃| 亚洲成av人片不卡无码久久| 亚洲色大成网站www久久九| 久久婷婷五月综合色奶水99啪| 国产精品一区二区久久| 亚洲国产香蕉人人爽成AV片久久 | 中文字幕无码久久人妻| 一本一本久久aa综合精品| 国产精品久久久久久久久鸭 | 久久99这里只有精品国产| 亚洲精品乱码久久久久66| 999久久久免费国产精品播放| 亚洲国产香蕉人人爽成AV片久久| 无码人妻久久一区二区三区免费| 丁香五月综合久久激情| 99久久做夜夜爱天天做精品| 91久久精一区二区三区大全| 亚洲性久久久影院| 99久久超碰中文字幕伊人| 久久综合五月丁香久久激情| 麻豆亚洲AV永久无码精品久久 | 久久久久亚洲Av无码专| 久久夜色精品国产www| 国产亚洲欧美精品久久久| 欧美一级久久久久久久大| 72种姿势欧美久久久久大黄蕉| 久久久久噜噜噜亚洲熟女综合| 久久精品水蜜桃av综合天堂| 色综合久久天天综线观看| 久久99热狠狠色精品一区| 久久精品国产亚洲AV影院| 久久av免费天堂小草播放| 97久久超碰成人精品网站| 久久久久亚洲AV片无码下载蜜桃| 99久久久久| 久久精品这里热有精品|