正文

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);

       //注意水平滚动条的影响,如果已经移动了水平滚动条,可能left0,或者超出总大小

       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;

       //bottomtop不用管

       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;

//peditCEdit对象的指针,提供接口,只要在程序中让pedit指向一个对象即可

       pedit->MoveWindow(rect,TRUE);

       pedit->ShowWindow(TRUE); 

       pedit->SetFocus();

}

 

 

 

^_^!这样就完成了.效果还可以.当然你还要去响应CEdit失去焦点和得到焦点的事件.这个就不是我的任务了,因为每个人的要求不一样啊!

看看我的效果!

 


阅读(5694) | 评论(1)


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

评论

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