【第22期】观点:IT 行业加班,到底有没有价值?

如何使CListCtrl完全可编辑

转载 2012年03月23日 09:23:04

专题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();

         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失去焦点和得到焦点的事件.这个就不是我的任务了,因为每个人的要求不一样啊!

看看我的效果!

举报

相关文章推荐

CListCtrl的使用完全指南

CListCtrl的使用完全指南 转自:http://www.programbbs.com/doc/2887.htm创建图形列表并和CListCtrl关联: m_image_list.Create(I...

MFC CListCtrl 使用介绍

列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值。MFC中使用CListCtrl类来封装列表控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT&amp; rect, CWnd* pParent...

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

MFC CListCtrl 使用介绍

列表控件可以看作是功能增强的ListBox,它提供了四种风格,而且可以同时显示一列的多中属性值。MFC中使用CListCtrl类来封装列表控件的各种操作。通过调用 BOOL Create( DWORD dwStyle, const RECT&amp; rect, CWnd* pParent...

CListCtrl控件的使用指南

创建图形列表并和CListCtrl关联: m_image_list.Create(IDB_CALLER2, 16, 10, RGB(192,192, 192)); m_image_list.Set...

简单的VC基础教程

VC基础教程 序言及版权说明 1999/09/05</b
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)