我要在clistctrl控件中添加按钮,每增加一行,在第m_iBtnColumn列要添加一个按钮,这个按钮是始终可见的。
  我该怎么实现这个功能,我现在重载了CListCtrl,在OnPaint()函数中这样做:先删除原来的按钮,再添加新按钮,但是有时点击按钮时,会失去焦点,而且点多了,会出错,代码如下:   CArray<CButton*,CButton*> m_ButtonList;void CListCtrlEx::OnPaint() 
{
///删除原来的Button
int iBtnCount;
iBtnCount = m_ButtonList.GetSize();
TRACE1("iBtnCount = %d\n",iBtnCount);
for(int i = 0;i < iBtnCount;i++)
{
CButton *pBn;
pBn = m_ButtonList.GetAt(0);
m_ButtonList.RemoveAt(0);
pBn->DestroyWindow();
if(pBn)
   delete pBn;
}
// m_ButtonList.RemoveAll();
TRACE1("After iBtnCount = %d\n",m_ButtonList.GetSize());    ////创建新Button
CHeaderCtrl *pHeader = GetHeaderCtrl();
int iListCount;
iListCount = GetItemCount();
TRACE1("*****************Item Count = %d\n",iListCount);
for(i = 0;i < iListCount; i++)
{

DWORD dwStyle;
CRect ColRt;
CRect rt;
pHeader->GetItemRect(m_iBtnColumn,&ColRt);
                GetItemRect(i,&rt,LVIR_LABEL);
rt.top += 1;
rt.bottom -=1;
rt.left += ColRt.left;
rt.right = rt.left + ColRt.Width() - 4;

dwStyle = WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON;
                CButton *pButn= new CButton();
pButn->Create("发送",dwStyle,rt,this,BUTTON_ID + i);
// pButn->SetButtonStyle()
pButn->ShowWindow(SW_SHOWNORMAL);
m_ButtonList.Add(pButn);
TRACE1("^^^^^^^^^^^^^^^^^^^Button Count = %d\n",m_ButtonList.GetSize());
}
CListCtrl::OnPaint();
   }
    请高手指点,我哪里出错了??这样做是个好方案吗,该怎么实现?

解决方案 »

  1.   

    先说你的方案吧,坦白说:很不好!
    你在OnPaint中添加删除按钮,严重影响效率!
    要知道,不管有没有添加行,只要你的控件的客户区需要重绘,都会调用这个函数.就是不管你有没有添加新行,它都很可能进行删除添加按钮.
      

  2.   

    是的,我也知道不好。我是从CodeProject上看到一个添加ProcessControl的例子上这么做的,所以我也照葫芦画瓢了。求教大侠,说说更好的办法贝,我不知道更好的办法是什么
      

  3.   

    你好象要实现的效果是当CLsitCtrl每添加一行,CArray<CButton*,CButton*> m_ButtonList;就添加一个和他对应的按钮,是吧.
    如果是这样的话.可以在添加行的函数中在CLsitCtrl的最后添加一行,再添加对应的按钮.
    如果是在CLsitCtrl的中间插入一行的话,为了保持其对应关系,只有象你那样全部删除再添加.你要保持主要是行和按钮的一一对应关系.
    我主要说的是添加一个函数来处理添加/插入CLsitCtrl的行操作和添加对应的按钮.
    说的太乱了,不知道你明白没有.
      

  4.   

    另外把你的for(int i = 0;i < iBtnCount;i++)
    {
    CButton *pBn;
    pBn = m_ButtonList.GetAt(0);
    m_ButtonList.RemoveAt(0);
    pBn->DestroyWindow();
    if(pBn)
       delete pBn;
    }
    该成     CButton *pBn=NULL;
             for(int i = 0;i < iBtnCount;i++)
    {
    pBn = m_ButtonList.GetAt(0);
    m_ButtonList.RemoveAt(0);
    pBn->DestroyWindow();
    if(pBn)
                      {
       delete pBn;
                         pBn=NULL;
                       }
                      
    }
    我认为是造成你的"有时点击按钮时,会失去焦点,而且点多了,会出错"的主要原因.
    你把添加按钮的操作放在OnPaint中,只要是操作正确的话,虽然效率低,但不会出错.
      

  5.   

    我现在正按照你说的,添加一个CListCtrlEx::InsertItemEx(int nItem, LPCTSTR lpszItem)函数,在这个函数里面添加按钮,再调用CListCtrl::InsertItem(nItem, lpszItem );不过按钮创建的时候,得不到相应行列的CRect值,应该是该行还没有被创建,所以GetItemRect(i,&rt,LVIR_LABEL); 返回的rt不正确
      

  6.   

    如果不在OnPaint()中实现插入按钮,是不是还不行,否则没法实现按钮随该列变宽
    而变宽,我需要有这个功能。
      

  7.   

    关于GetItemRect(i,&rt,LVIR_LABEL); 的问题,
    方法1,先CListCtrl::InsertItem(nItem, lpszItem ),再添加按钮
    方法2.因为在CListCtrl中,每行都差不多,调用上一行的"骗骗"它.
      

  8.   

    CListCtrl有LVN_BEGINDRAG和LVN_ENDDRAG消息,添加他的处理函数,如果是在拖你的按钮列的话则重新删除添加!
    哎,这样的话虽然计算机会轻松点,但你会累点!呵呵,
      

  9.   

    我现在是按照方法1,先InsertItem,然后再添加按钮。  
       我现在想自己重载headerCtrl被拖动的函数,然后MoveWindow,把按钮移到新位置,
    也这样也不用重新删除,再添加,不过我响应LVN_BEGINRDRAG和HDN_BEGINDRAG,还有HDN_ITEMCHANGING,为什么,拖动header头,改变列宽时,消息都走不到这些消息,
    我该怎么处理呢
      

  10.   

    我自己封装的个类,发给你哈,希望对你有所帮助.
    CSortList::CSortList(CImageRetrievalView* pv)
    {
    m_bAsc= TRUE;
    //this->m_nSortedCol = -1;
    CreateSortIcons();
    //GetHeaderCtrl()->SetImageList(&m_imglstSortIcons);
    pView = pv;
    }CSortList::~CSortList(void)
    {
    m_imglstSortIcons.DeleteImageList();
    m_bmpUpArrow.DeleteObject();
    m_bmpDownArrow.DeleteObject();
    }//IMPLEMENT_DYNCREATE(CsercurityView, CFormView)
    BEGIN_MESSAGE_MAP(CSortList, CListCtrl)
    ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnLvnColumnclick)
    END_MESSAGE_MAP()
    /////////////////////////////////////////////////////////////////////////////
    // CSortList message handlersvoid CSortList::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
    {
    LPNMLISTVIEW pNMListView = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    // TODO: Add your control notification handler code here
    //NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    if( pNMListView->iSubItem == m_nSortedCol )
    m_bAsc = !m_bAsc;
    else
    {
    m_bAsc = FALSE;
    m_nSortedCol = pNMListView->iSubItem;
    }
    SortItems( ListCompare, (DWORD)this ); 
    SetSortIcon();
    for  (int i=0;i<this->GetItemCount();i++)   
    this->SetItemData(i,   i);  
    pView->Invalidate();
    *pResult = 0;
    }
    void CSortList::CreateSortIcons()
    {
    if (!m_imglstSortIcons.m_hImageList)
    {
    COLORMAP cm = {RGB(0, 0, 0), GetSysColor(COLOR_GRAYTEXT)};
    m_imglstSortIcons.Create   (9, 5, ILC_COLOR24 | ILC_MASK, 2, 0);
    m_bmpUpArrow.LoadMappedBitmap(IDB_HDRUP, 0, &cm, 1);
    m_nUpArrow = m_imglstSortIcons.Add(&m_bmpUpArrow, RGB(255, 255, 255));
    m_bmpDownArrow.LoadMappedBitmap(IDB_HDRDOWN, 0, &cm, 1);
    m_nDownArrow = m_imglstSortIcons.Add(&m_bmpDownArrow, RGB(255, 255, 255));
    }
    }void CSortList::SetSortIcon()
    {
    CHeaderCtrl* pHeaderCtrl = this->GetHeaderCtrl();
    ASSERT(pHeaderCtrl);pHeaderCtrl->SetImageList(&m_imglstSortIcons);
    for( int col = 0; col< GetHeaderCtrl()->GetItemCount(); col++ )
    {
    HDITEM hdrItem = { 0,};hdrItem.mask = HDI_FORMAT | HDI_IMAGE;BOOL ret = pHeaderCtrl->GetItem(col-1, &hdrItem);
    ret = pHeaderCtrl->GetItem(col+1, &hdrItem);
    ret = pHeaderCtrl->GetItem(col, &hdrItem);
    if ( m_nSortedCol == col)
    {
    hdrItem.fmt = hdrItem.fmt & HDF_JUSTIFYMASK | HDF_IMAGE | HDF_STRING | HDF_BITMAP_ON_RIGHT;
    if( m_bAsc )
    hdrItem.iImage = m_nUpArrow;
    else
    hdrItem.iImage = m_nDownArrow;
    }
    else
    {
    hdrItem.fmt = hdrItem.fmt & HDF_JUSTIFYMASK | HDF_STRING;
    }
    pHeaderCtrl->SetItem(col, &hdrItem);
    }
    }bool CSortList::GetFullRowSelect()
    {
    return ( GetExtendedStyle()&LVS_EX_FULLROWSELECT) == LVS_EX_FULLROWSELECT;
    }void CSortList::SetFullRowSelect( bool bFullRowSelect )
    {
    if( bFullRowSelect )
    SetExtendedStyle( GetExtendedStyle()|LVS_EX_FULLROWSELECT );
    else
    SetExtendedStyle( GetExtendedStyle()&(~LVS_EX_FULLROWSELECT) );  
    }bool CSortList::GetGridLines()
    {
    return ( GetExtendedStyle() & LVS_EX_GRIDLINES ) == LVS_EX_GRIDLINES;
    }void CSortList::SetGridLines( bool bGridLines )
    {
    if( bGridLines )
    SetExtendedStyle( GetExtendedStyle()|LVS_EX_GRIDLINES );
    else
    SetExtendedStyle( GetExtendedStyle()&(~LVS_EX_GRIDLINES) );  
    }int CALLBACK CSortList::ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
    CSortList* pList=(CSortList*)lParamSort;
    int nItem1, nItem2; LVFINDINFO FindInfo; 
    FindInfo.flags = LVFI_PARAM;    // 指定查找方式
    FindInfo.lParam = lParam1; 
    nItem1 = pList->FindItem(&FindInfo, -1); // 得到对应Item索引
    FindInfo.lParam = lParam2; 
    nItem2 = pList->FindItem(&FindInfo, -1); if((nItem1 == -1) || (nItem2 == -1)) 

    TRACE("无法找到!\n"); 
    return 0; 
    } CString Str1,Str2; 
    Str1 = pList->GetItemText(nItem1, pList->m_nSortedCol); // 得到排序列的Text
    Str2 = pList->GetItemText(nItem2, pList->m_nSortedCol); 
    int iCompRes = 0;
    if(Str1 > Str2) 
    iCompRes = 1; 
    else if(Str1 == Str2) 
    iCompRes = 0; 
    else 
    iCompRes = -1;if(pList->m_bAsc)
    return iCompRes;
    else
    return iCompRes*-1;
    return 0;
    }
      

  11.   

    不好意思  ,刚才复制时不小心发错了,  SORRY.
      

  12.   

    你的OnLvnColumnclick函数什么时候会被响应啊,我怎么响应不了
      

  13.   

    有了点进展,又出现了新问题,我在CListCtrlEx中重载了ON_NOTIFY(HDN_ITEMCHANGINGA, 0, OnHdnItemchanging)对OnHdnItemchanging()函数做了处理,然后同样的程序在xp的机器上可以正常的运行,结果也正确,不过在2003server中却还有刷新问题。即拖动时按钮并没有改变大小,在下次再拖动时,按钮才变到上一次拖动的大小。这是什么原因啊
      

  14.   

    我也认为是刷新问题.
    你可以先试试简单点的Invalidate(),让整个客户区重绘.
    不行的话,重绘背景,返回TRUE.
    我想也就这两方面的原因吧
      

  15.   

    感觉 lz 对界面 不怎么熟悉。当然我不是指 细节。 是 一些原理吧。
    通常来说 界面的 画啊,鼠标等动作 都是 有对应的 消息,需要修改界面 都可以通过对消息的处理 或者重载函数 等实现。。明白这些 可以去msdn 里面查找。同时 对你的界面设计帮助会比较大。 不好意思,我没有去帮你实现代码, 空说了一些。希望有所帮助。
      

  16.   

    2003server的那个问题已经确定了,应该是操作系统的问题。因为在xp上静态编译的程序,在2003上也执行的不一样。
        其他的还有个小问题,请教一下,就是我加的按钮,其他都还满意,就是滚动条,往下滚动时,按钮会把HeaderCtrl盖上,这不是我想要的结果,我需要的是HeaderCtrl在最上边,能提供些思路吗
      

  17.   

    感谢各位的提示。。我也成功的在listview中加了按钮的问题,我的方法是:
    添加一个InsertItemEx函数,在其中添加按钮
    重载OnPaint(知道效率不高),在其中计算然后Btn->MoveWindow,把按钮移到新位置
    最后也遇到了LZ的问题。。就是滚动条,往下滚动时,按钮会把HeaderCtrl盖上,这不是我想要的结果,我需要的是HeaderCtrl在最上边,能提供些思路吗不过,最终我解决了:
    办法就是:
    if ( rt.top < ColRt.bottom) //按钮的顶端已经超过了HeaderCtrl的底端
    pBtn->ShowWindow(SW_HIDE); 
    else
    pBtn->ShowWindow(SW_SHOWNORMAL);