正文

CListCtrl学习笔记(2)---中级篇(1)2006-12-24 14:53:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/yuqiexing/21881.html

分享到:

专题1: 如何使CListCtrl完全可编辑?     1.       背景 : 我们知道如果CListCtrl是报表样式,那么CListCtrl所提供的编辑功能只局限于第一列.也就是说只有第一列可编辑.这样显然无法满足一般数据库的要求.我们想要每个子项都能编辑.     2.       思路 : CEdit是一个很好的可控制编辑控件.如何把CEdit和我们的CListCtrl联系起来?一种很好的想法是------一般我们如果想编辑某一项,那么就应该去双击.双击以后就让CEdit在那里显示,当然要把大小调整和子项表格一样.如果CEdit失去了焦点,表示修改完毕,那么立即更改子项的数据,同时让CEdit隐藏.因为每次只能编辑一项,所以只需要一个CEdit就够了.     3.       方法: (1)    首先从CListCtrl派生一个类,其他已经有的变量或者函数设置我已经介绍,如果不清楚的读者,可以去参考”基础篇”.   (2)    有一点可以肯定,我们必须响应双击事件: void Cmylist::OnLButtonDblClk(UINT nFlags, CPoint point) { int index;//行号 int colnum;//列号 GetWindowRect(r);//稍后说明 GetParent()->ScreenToClient(r);//稍后说明   if((index=HitTestEx(point,&colnum))!=-1)     EditSubItem(index,colnum);   CListCtrl::OnLButtonDblClk(nFlags, point); } 其中HitTestEx是用来求出双击点所在的行列号,如果行号不为-1,那么就调用函数EditSubItem. 这个函数会根据行列号求出该子项具体坐标,方便CEdit调整位置.     (3)    如何求出行列号?行号是很好求出来的 ,但是列号就不是很简单了,必须详细判断. int Cmylist::HitTestEx(CPoint &point, int *pcolumn) {        int columnNum=0; //获取页面内首行索引号,不一定是0,要考虑滚动条的情况 int row=GetTopIndex(); // GetCountPerPage()获取在页面内行的总数        int bottom=row+this->GetCountPerPage();        // 防止超出范围        if(bottom>this->GetItemCount())               bottom=GetItemCount();        //获取列的总数        int ncolumncount=this->GetHeaderCtrl()->GetItemCount();        //可以肯定双击点肯定在页面内,因此从页面首行索引号开始判断        for(;row<=bottom;++row)        {               CRect rect;               //求出行的rect               GetItemRect(row,&rect,LVIR_BOUNDS);               //点是否在行的矩形内               if(rect.PtInRect(point))               //如果点在行的矩形内,求出点在哪一列                      for(columnNum=0;columnNum<ncolumncount;columnNum++)                      {                             //求出列的宽度                             int colwidth=this->GetColumnWidth(columnNum);                             if(point.x>=rect.left&&point.x<=(rect.left+colwidth))                             {                                    *pcolumn=columnNum;                                    return row;                             }                             rect.left+=colwidth;                      }        }        return -1; } 当然上面那种方法有点复杂,是完全从头开始判断.其实我们可以先利用CListCtrl提供的函数求出行号,再求列号,这样稍微简单点 int Cmylist::HitTestEx(CPoint &point, int *pcolumn) {        int columnNum=0;        int row=HitTest(point);//求出行号    int ncolumncount=this->GetHeaderCtrl()->GetItemCount();            (2007.1.3更新)                LVHITTESTINFO Info;       Info.pt=point;       this->SubItemHitTest(&Info);      *pcolumn=Info.iSubItem;       if(*pcolumn>=0&&*pcolumn<ncolumncount)      return row;       else        return -1;       /* int ncolumncount=this->GetHeaderCtrl()->GetItemCount();                      CRect rect;               GetItemRect(row,&rect,LVIR_BOUNDS);               if(rect.PtInRect(point))                      for(columnNum=0;columnNum<ncolumncount;columnNum++)                      {                             int colwidth=this->GetColumnWidth(columnNum);                             if(point.x>=rect.left&&point.x<=(rect.left+colwidth))                             {                                    *pcolumn=columnNum;                                    return row;                             }                             rect.left+=colwidth;                      }*/               }     (4)    求出具体CEdit移动坐标 int Cmylist::Item_X(int row, int column,CRect& rect_X) {          int offset=0;        for(int i=0;i<column;i++)               offset+=GetColumnWidth(i);        CRect rect;        GetItemRect(row,rect,LVIR_BOUNDS);        //注意水平滚动条的影响,如果已经移动了水平滚动条,可能left为0,或者超出总大小        if(offset+rect.left<0||offset+rect.left>client_rect.right)        {               CSize size;               //offset肯定为正,如果出现了rect.left为负               if(offset+rect.left>0)                      size.cx=- (offset+rect.left);               else                      size.cx=offset+rect.left;               size.cy=0;//垂直不用管               //如果某一列的一半在滚动条左边,一半在右边,就再次调整滚动条的位置.               Scroll(size);               rect.left - =size.cx;        }        rect.left+=offset+2;        rect.right=rect.left+GetColumnWidth(column)-2;        //bottom和top不用管        rect_X=rect;        return rect.right; }       (5)    移动CEdit   void Cmylist::EditSubItem(int Item, int Column) {        CRect rect;        //求出行列所在rect        this->Item_X(Item,Column,rect);        EditCellShow(rect,Item,Column,r); }       void Cmylist::EditCellShow(CRect rect, int Item, int Column,CRect r)   {        //还记得r吗?在开始的双击函数OnLButtonDblClk中,它是CListCtrl在父窗口中的位置     rect.left+=r.left;        rect.top+=r.top+2;        rect.right+=r.left;        rect.bottom+=r.top+2; //pedit是CEdit对象的指针,提供接口,只要在程序中让pedit指向一个对象即可        pedit->MoveWindow(rect,TRUE);        pedit->ShowWindow(TRUE);         pedit->SetFocus(); }       ^_^!这样就完成了.效果还可以.当然你还要去响应CEdit失去焦点和得到焦点的事件.这个就不是我的任务了,因为每个人的要求不一样啊! 看看我的效果!  

阅读(5951) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册