我创建了ListView控件,可是发现它只能显示数据,却不能修改。如何才能让它象浏览数据库那样可以修改呢?

解决方案 »

  1.   

    ListView默认不提供编辑功能,一般如果要实现“表面上”的编辑效果的话,就动态创建一个编辑框,并且将它的大小和位置设置为你要编辑的ListCtrl中的“单元格”的大小和位置,也就是覆盖在它上面,这样就可以实现“表面上”的编辑效果.
      

  2.   


    /****************************************************************************
    1.在ListView类的OnInitialUpdate里面添加LVS_EDITLABELS属性 void CEditListViewView::OnInitialUpdate()
    {
    CListView::OnInitialUpdate();
    CListCtrl& m_ListCtrl=GetListCtrl();

    //设置基本样式
    LONG lStyle;
    lStyle=GetWindowLong(m_ListCtrl.m_hWnd, GWL_STYLE); //获取当前窗口style
    lStyle |=LVS_REPORT ; //以详细资料即报告方式显示;
    lStyle |=LVS_SHOWSELALWAYS ; //一直显示被选中表项方式;
    lStyle |=LVS_EDITLABELS ; //可编辑;
    SetWindowLong(m_ListCtrl.m_hWnd, GWL_STYLE, lStyle);//设置style 。
    }
    2.在Frame类里添加虚函数:DefWindowProc,和以下代码: LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
    {
    if (message==WM_NOTIFY)
    {
    LPNMHDR pnmh =(LPNMHDR) lParam; 
    if (pnmh->code==LVN_ENDLABELEDIT)
    { CListCtrl& m_ListCtrl=((CListView*)GetActiveView())->GetListCtrl(); LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pnmh;
    LVITEMA item = pDispInfo->item;
    CString str = item.pszText;
    str.TrimLeft();
    str.TrimRight();
    if (str.GetLength() > 0)
    m_ListCtrl.SetItemText(item.iItem,item.iSubItem,item.pszText);
    } }
    return CFrameWnd::DefWindowProc(message, wParam, lParam);
    }3.一切ok!愿顺利!阿弥陀佛!
    例子代码下载:(请不要使用下载工具,否则可能出错)
    http://cid-3ba16e78a53d2d3d.office.live.com/self.aspx/VC/EditListView.zip****************************************************************************/
      

  3.   

    感谢楼上!我忘了说了,我用的是C/SDK,我猜想C++中的ListView可以编辑,是因为C++的类中增添的功能。所以使用C的我,无法使用。可能还是象某些朋友说的那样,Windows提供的ListView控件本来就是没有编辑功能的。要想它有编辑功能,只能自己用编辑框模拟实现。这就要求获得单元格的大小和位置。单元格的长度好办,在设置的时候自己就需要设置这个参数,因为容易获得,那高度呢?还有位置?位置只能自己获得单元格的索引号,然后自己计算出来?
      

  4.   


    GetWindowRect获取窗口的大小和位置,可能要调用ClientToScreen函数转换坐标;
    CRect rt;
    GetWindowRect(rt);
    然后动态创建一个编辑框,调用SetWindowPos将它的大小设置为rt.Width和rt.Height,还有位置rt.x,rt.y;
    当你输入了你的内容后,将此编辑框的内容更新到ListCtrl的“单元格”中,可以调用SetWindowText,也可以直接发消息...
      

  5.   

    可是据说ListView的每个单元格并不是单独的控件,也就不是一个窗口,好象不能用GetWindowRect
      

  6.   

    C:
    LVM_GETITEMRECT
    LVM_GETSUBITEMRECT
    VC:
    CListCtrl::GetItemRect
    CListCtrl::GetSubItemRect
      

  7.   

    先获取“单元格”的指针,再GetWindowRect,也可以如楼上
    CListCtrl::GetItemRect和CListCtrl::GetSubItemRect
      

  8.   

    非常感谢!原来还有个LVM_GETSUBITEMRECT消息。
    我查了一下MSDN,对它的一个参数有点不清楚,就是那个接受位置的RECT结构:
    lpRect 
    Long pointer to a RECT structure that receives the subitem bounding rectangle data. The members of RECT must be initialized according to the member and value relationships shown in the following tables. 
    Member Value  
    top  The one-based index of the subitem.  
    left  Flag value (see following). Indicates the portion of the list-view subitem for which to retrieve the bounding rectangle.  Value Description 
    LVIR_BOUNDS  Returns the bounding rectangle of the entire item, including the icon and label.  
    LVIR_ICON  Returns the bounding rectangle of the icon or small icon.  
    LVIR_LABEL  Returns the bounding rectangle of the entire item, including the icon and label. This is identical to LVIR_BOUNDS.  上面的内容似乎是说在发送这个消息的时候,RECT结构的TOP字段必须填上子项目索引,LEFT字段必须填上标志,这个标志只可能是LVIR_BOUNDS,LVIR_ICON和LVIR_LABEL三种,而第一种和第三种完全相同,返回RECT的内容是"entire item“的边界。请问这个entire item的边界,是指整个项目(包括主项目和所有子项目)的边界,还是指这一个子项目的所有的边界(包括图标和标签)?
      

  9.   

    可是,如何获得鼠标单击时的子项目的索引呢?在NM_CLICK消息中,如何用LVM_GETNEXTITEM消息只能获得项目的索引,无法获得子项目的索引,有时候我要编辑的是子项目。怎么办?
      

  10.   

    // NM_CLICK消息
    void CXXXDlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    // TODO: Add your control notification handler code here
    NMLISTVIEW* pList = (NMLISTVIEW*)pNMHDR;
    int nItem = pList->iItem;
    if(nItem)
    {
    int nSubItem = pList->iSubItem;
    CString str;
    str.Format(_T("Item: %d, SubItem: %d"), nItem, nSubItem);
    AfxMessageBox(str);
    }
    *pResult = 0;
    }
      

  11.   

    case NM_CLICK:
    {
    LPNMITEMACTIVATE pItemActivate = (LPNMITEMACTIVATE)lParam;
    if ( pItemActivate == NULL ) return S_OK;  
    int nItem = pItemActivate->iItem ;
    int nSubItem = pItemActivate->iSubItem ;
    看这个nSubItem
      

  12.   

    感谢以上两位网友,你们的方法好象都是把lParam的内容强制转换成某结构指针,此结构有iItem和iSubItem成员。我试了一下,结果是这样的:当点击某主键的时候,iItem值显示正确,iSubItem值也显示正确(为0)当点击某子键的时候,iTtem显示-1,iSubItem显示正确,为该项目的子项目号。而且还有一个差别,就是点击主键以后,会选中该主键,而点击子键,并不选中该子键。其实选不选中没有关系。我现在的困难是:如果点击子键,那子键索引显示正确,可是主键索引显示不正确怎么办?(和点击屏幕空白处一样,均显示为-1)。或者还是只能再用别的消息来获取该项的主键索引号?
      

  13.   

    点击屏幕空白处,则iItem和iSubItem均显示为-1
      

  14.   

    Sorry,这里修改一下
    if(nItem)
    --》
    if(-1 != nItem)
      

  15.   

    感谢!是啊,我试了一下,点击列表视图的某处,iSubItem总能正确显示,只要鼠标点击处的坐标在它这一列就行,哪怕此处并无内容。如果点击到最右边没有内容处,则显示为-1可是主键,也就是iTtem,只有在点击主键的时候,才显示正确的值,否则总显示为-1.这给我出了一个难题。我的目的就是点击某个键(主键或者子键),就可以编辑它。所以必须获得主键和子键的索引。主键没问题了,可是点击子键的时候,主键的索引号(iItem)的值总显示为-1,也就是说无法获得主键的索引号。当然问题的解决方法我想到:是不是再用GETNEXTITEM消息来获得当前焦点的主键值。一来这个太麻烦,二来,点击子键,难道就能使主键获得焦点吗?我真是搞不懂,要是能在这里有办法解决一下就好了。
      

  16.   

    果然,正象我担心的那样,点击子键不能获得焦点。我用nIndex = SendMessage(hList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED);来获得焦点。结果发现:点击主键时,焦点位置可以正确显示,而点击子键时,焦点位置还是原来的焦点位置,不随点击子键的变化而变化。这可难办了!如何获得某个子键的位置和大小呢?
      

  17.   

    case NM_CLICK:
    是发给 listview的 父窗口的。
    case NM_DBLCLK:
    OnItemDBLCLK(lParam) ;
    break;OnItemDBLCLK(LPARAM lParam) 
    {
    LPNMITEMACTIVATE pItemActive = (LPNMITEMACTIVATE)lParam ;
    _ASSERT(pItemActive);
    int nItem = pItemActive->iItem ;
    int nSubItem = pItemActive->iSubItem ;
    if ( m_bEditable && nItem >= 0 && nSubItem >= 0 && !IsGroupItem(nItem) && TRUE == GetCellEditable(nItem,nSubItem) )
    {
    DWORD dwUserData = 0 ;
    //Create in-place edit
    CreateInPlaceEdit(nItem,nSubItem,dwUserData) ;
    }
    不行的话,把code upload 到 bbs.aisnote.com 我给你看看
      

  18.   


    学习中,原来在CListBox控件中实现编辑功能时,都是在响应行动态创建一个编辑控件,编辑完后再更新列表框的内容,
    在CListview 中直接就有可编辑属性?回去试试
      

  19.   

    http://www.codeproject.com/KB/list/ListsiEdit.aspx
    我也找了好久才找、、、