写了一个监听端口程序,发现将每次收到的数据信息显示在屏幕上时,每显示一条就会刷新一下屏幕,导致在压力测试时,由于数据量大,屏幕不停的闪烁.请大家看看,有没有好的显示方式,我的显示部分是如下实现的:
void CMainFrame::InsertMsgView(CListCtrl * pListView, CReceiveMsg * pMsg)
{
CTime time; LV_ITEM lvItem; 
lvItem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_STATE;
lvItem.state=LVIS_FOCUSED|LVIS_SELECTED ;
lvItem.stateMask=LVIS_FOCUSED|LVIS_SELECTED;
lvItem.iImage=pMsg->GetDataFlag();
lvItem.iItem=0;
lvItem.iSubItem=0;
lvItem.pszText="";
pListView->InsertItem(&lvItem);
//接收时间
time=pMsg->GetReceiveTime();
pListView->SetItemText(0,1,time.Format("%Y/%m/%d %H:%M:%S"));
//终端
pListView->SetItemText(0,2,pMsg->GetTerminalID());
//卡号
// pListView->SetItemText(0,3,pMsg->GetCardID());
//流水号
pListView->SetItemText(0,3,pMsg->GetSystrace());
//票据号
pListView->SetItemText(0,4,pMsg->GetTicket());
//交易类型
pListView->SetItemText(0,5,pMsg->GetTxnType());
//交易金额
pListView->SetItemText(0,6,pMsg->GetAmt());
//交易结果
pListView->SetItemText(0,7,pMsg->GetTrans_Result());
//操作员
pListView->SetItemText(0,8,pMsg->GetOperator());
//客户机信息
pListView->SetItemText(0,9,pMsg->GetClientIP());
UINT nPort=pMsg->GetClientPort();
CString strPort;
strPort.Format("%d",nPort);
pListView->SetItemText(0,10,strPort);
    //下发时间
time=pMsg->GetSendTime();
pListView->SetItemText(0,11,time.Format("%Y/%m/%d %H:%M:%S"));
    //上送数据包
pListView->SetItemText(0,12,pMsg->GetReceiveData());    CDC *pDC=pListView->GetDC();
CPen pen(PS_SOLID,4,RGB(255,0,0));
pDC->SelectObject(&pen);
CRect rcLabel;
pListView->GetItemRect(2,rcLabel,LVIR_LABEL);
   
// CPoint point(rcLabel.left,rcLabel.bottom);
// pDC->MoveTo(point);
// pDC->LineTo(CPoint(400,300));
return ;
}

解决方案 »

  1.   

    CDC *pDC=pListView->GetDC();
    CPen pen(PS_SOLID,4,RGB(255,0,0));
    pDC->SelectObject(&pen);
    CRect rcLabel;
    pListView->GetItemRect(2,rcLabel,LVIR_LABEL);
    你只是取得了一个ITEM的Rect,什么都没做,下面都注释了,是做什么用呢?另外记得ReleaseDC(pDC);
      

  2.   

    m_list.SetRedraw(FALSE);
    //更新内容
    m_list.SetRedraw(TRUE);
    m_list.Invalidate();
    m_list.UpdateWindow();
      

  3.   

    To: wenbaby(雯贝贝)
    请问一下怎么设置使它追加在最后啊, 是在lvItem里设置吗?
      

  4.   

    lvItem.iItem=0;
    把0换成实际的数目即可。
      

  5.   

    To:wenbaby(雯贝贝)
    非常谢谢你,我试了改成lvItem.iItem=1, 发现还是没有追加在最后啊,请问你所说的实际的数目是指什么啊?是非零吗?
      

  6.   

    LV_ITEM lvItem;
    lvItem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_STATE;
    lvItem.state=LVIS_FOCUSED|LVIS_SELECTED ;
    lvItem.stateMask=LVIS_FOCUSED|LVIS_SELECTED;
    lvItem.iImage=pMsg->GetDataFlag();
    lvItem.iItem= pListView->GetItemCount() + 1;
    lvItem.iSubItem=0;
    lvItem.pszText="";
    pListView->InsertItem(&lvItem);
      

  7.   

    还有,就是等所有数据都插入以后再显示,可以吗?
    pListView->SetRedraw(FALSE);
    ..........//插入数据
    pListView->SetRedraw(TRUE);
      

  8.   

    To:lfchen(一条晚起的虫) 刚按你说的改写了一下,发现还是没有追加在最后啊?请多多指教,谢谢!
      

  9.   

    lvItem.iItem= pListView->GetItemCount() + 1; // 不需要加1
      

  10.   

    BOOL ClistboxView::OnEraseBkgnd(CDC* pDC)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
             //可以消除闪烁,但是会有副作用,可以判断一下,在添加行的时候,return true;    //其他时候呢return CListView::OnEraseBkgnd(pDC);
    return TRUE;
    //return CListView::OnEraseBkgnd(pDC);
    }
      

  11.   

    steps:
    1,增加一个private BOOL m_IsErase;并且初始化为TRUE//意思是默认擦除背景
    2.在插入行的函数最开始,写m_IsErase=FALSE;//要插入行了,我不想擦除背景
    3,重载OnEraseBkgndBOOL ClistboxView::OnEraseBkgnd(CDC* pDC)
    {
        if (m_IsErase)
        {
            //在需要的时候擦除背景。
            return CListView::OnEraseBkgnd(pDC);
        }
        else
        {
            //再不需要的时候,比如频繁插入行的时候,本次不擦除,恢复擦除状态
            m_IsErase=TRUE;
            return TRUE;
        }
    }
      

  12.   

    BOOL ClistboxView::OnEraseBkgnd(CDC* pDC)
    {
            // TODO: 在此添加消息处理程序代码和/或调用默认值
            if (m_IsErase)
            {
                    //m_IsErase=FALSE;
                    return CListView::OnEraseBkgnd(pDC);
            }
            else
            {
                    m_IsErase=TRUE;
                    GetClientRect(rc);
                    CListCtrl & ListCtrl=GetListCtrl();
                    
                    ListCtrl.GetItemRect(0,rc2,LVIR_BOUNDS );
                    //擦除背景的时候,把listview中行所在区域排除,只擦除之外的区域
                    pDC->FillSolidRect(rc2.right,rc2.top,rc.Width()-rc2.Width(),rc.Height(),RGB(255,255,255));
                    return TRUE;
            }
    }
      

  13.   

    CListCtrl & ListCtrl=GetListCtrl();
    long litemcount=ListCtrl.GetItemCount();
    CRect rc,rc2,rcLast;
    GetClientRect(rc);
    if (m_IsErase&&litemcount==0)
    {
    TRACE("OnEraseBkgnd: default\n");
    //当listview被清空的时候,需要填充整个区域
    pDC->FillRect(rc,&CBrush(RGB(255,255,255)));
    //CListView::OnEraseBkgnd(pDC);
    return TRUE;
    }
    else
    {
    m_IsErase=TRUE;
    if (litemcount>0)
    {

    TRACE("OnEraseBkgnd: rgn%d\n",m_IsErase);
    //得到第一个ITEM的rect
    VERIFY(ListCtrl.GetItemRect(0,rc2,LVIR_BOUNDS ));
    //得到最后一个ITEM的rect
    VERIFY(ListCtrl.GetItemRect(ListCtrl.GetItemCount()-1,rcLast,LVIR_BOUNDS ));
    CRgn   rgnA, rgnB;
    //从client rect创建RGN,该区域需要去掉headctrl所占区域
    VERIFY(rgnA.CreateRectRgn( rc2.left-2,rc2.top-2,rc.right,rc.bottom ));
    //如果最后一条记录的右下角坐标,已经超出了client rect那么只需要创建当前视图中包含ITEM,RGN
    //如果最后一条记录没有超出视图的区域,那么仅仅创建当前视图中现有ITEM所在RGN
    if (rcLast.bottom>rc.bottom)
    {
    VERIFY(rgnB.CreateRectRgn(rc2.left,rc2.top,rc2.right,rc.bottom));
    }
    else
    {
    VERIFY(rgnB.CreateRectRgn(rc2.left,rc2.top,rc2.right,rcLast.bottom));
    }

            //用client rgn区域与视图中item所占区域相减,得到需要擦除的区域
    int nCombineResult = rgnA.CombineRgn( &rgnA, &rgnB, RGN_DIFF);
    // pDC->FillSolidRect(rc2.right,rc2.top,rc.Width()-rc2.Width(),rc2.Height(),RGB(255,0,255));
            //用白色填充,也可以先取得现在的背景色,再填充
    pDC->FillRgn(&rgnA,&CBrush(RGB(255,255,255)));
    rgnA.DeleteObject();
    rgnB.DeleteObject();
    return TRUE;
    }
    }
      

  14.   

    上面这个就可以避免楼上的问题。不过item的背景色透明和替换,就是另外一个问题,需要再做些工作