CLISTCTRL 显示图片及大批量数据的加载速度与闪烁问题

CLISTCTRL 显示图片及大批量数据的加载速度与闪烁问题

一般在用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(
210 160 , ILC_COLOR24  |  ILC_MASK,  8 1 );
        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;
};

你可能感兴趣的:(CLISTCTRL 显示图片及大批量数据的加载速度与闪烁问题)