list 高级功能

来源:互联网 发布:易语言支付宝转账源码 编辑:程序博客网 时间:2024/05/21 09:56
(要求不但能够在List Control中显示数据,而且能够动态修改选中的Item中的内容,其功能类似与在程序中插入一张可以随意修改的表(Table)。虽然整个过程很简单,却体现了MFC编程的灵活性。通过实现高级List Control控件,也可以从更深层次理解MFC界面编程。
下面将实现步骤总结如下:
这里我们来实现一个自己的类CEditTable,该类继承与CListCtrl。
先说一下我们的思路:CListCtrl类给提供了现实数据的基本操作,但要像Word中编辑表格一样编辑ClistCtrl中的内容,首先必须获取要编辑的Item的位置,然后用新输入的内容代替原来Item中的内容。基本思路很简单,就是先触发输入操作,然后新建一个CEdit编辑框对象,从CEdit编辑框中获取新的内容,以新内容替换指定Item中的内容,回车结束,销毁CEdit编辑框对象。下面来一步步实现。
1.  从CEdit控件继承一个CItemEdit类,作为CListCtrl的成员,用来接收输入内容。
2.  重载CEdit的消息翻译函数BOOL PreTranslateMessage(MSG* pMsg); 在函数中拦截ESC键和RETURN键按下的消息,解释为WM_KILLFOCUS消息(ESC和ENTER分别表示取消输入和输入结束)
BOOL CItemEdit::PreTranslateMessage(MSG* pMsg) 
{
    //拦截ESC键和RETURN键按下的消息,解释为WM_KILLFOCUS消息,这里也可以根据需要设置其它键作为输入结束或取消输入的标志
    if( pMsg->message==WM_KEYDOWN )
    {
        if( pMsg->wParam==13 )        //回车键


            pMsg->message = WM_KILLFOCUS;
        else if( pMsg->wParam==27 )    //ESC键
        {




            m_bInputValid = FALSE;    //此时的编辑结果无效
            pMsg->message = WM_KILLFOCUS;
        }
    }
    


    return CEdit::PreTranslateMessage(pMsg);
}
3. 重载OnKillFocus函数
void CItemEdit::OnKillFocus(CWnd* pNewWnd)
{
    // 得到父窗口,并通知父窗口结束编辑过程
    lj_CListCtrl *parent = (lj_CListCtrl *)GetParent();
    if( parent )
        parent->MyEndEdit( m_bInputValid );


    m_bInputValid = TRUE;
   
    CEdit::OnKillFocus(pNewWnd);
}
4.   从CListCtrl类继承新的CEditTable类
5.   在CEditTable中分别添加编辑控件成员 CItemEdit  m_edit; 便是行和列的坐标变量
              int m_nItem;   //被编辑表项的行号
             int m_nSubItem; //列号




6.   在CEditTable中重载鼠标左键按下消息的回调函数 void OnLButtonDown(UINT nFlags, CPoint point);


              应用中要通过点击鼠标左键开始编辑Table中的某一项。
void CEditTable::OnLButtonDown(UINT nFlags, CPoint point)
{
    POSITION pos;
    BOOL bSelected = FALSE;




    // 检查是否有Item正被编辑
    if( m_bEditing ==TRUE)
        goto defalt_session;


    // 检查是否有Item被选中,没有时不进入编辑


    pos = GetFirstSelectedItemPosition();
    if( pos )
    {
        // 得到被点击的Item
        LVHITTESTINFO testinfo;
        testinfo.pt.x = point.x;




        testinfo.pt.y = point.y;            //点击时的鼠标位置
        testinfo.flags = LVHT_ONITEMLABEL;    //点击的必须是标题
        if( SubItemHitTest(&testinfo)<0 )
            goto defalt_session;            //没有点在有效区域,不进入编辑
        m_nItem = testinfo.iItem;            //被点击表项的行号
        m_nSubItem = testinfo.iSubItem;    //被点击表项的列号


        //if(m_nSubItem == 0)
        //{
            //goto defalt_session;            //选中第一列,不编辑


        //}


        // 检查该表项是否被选中,没被选中不进入编辑
        while( pos )
            if( m_nItem==GetNextSelectedItem(pos) )


            {
                bSelected = TRUE;
                break;
            }
        if( bSelected==FALSE )
            goto defalt_session;            //没有点在有效区域,不编辑


        // 开始编辑
        m_bEditing = BeginEdit();
        return;


    }


defalt_session:
    CListCtrl::OnLButtonDown(nFlags, point);
}
7.   添加开始编辑函数BOOL BeginEdit();  完成新建CEdit对象、获取Edit输入文字等功能
BOOL CEditTable::BeginEdit()
{
    // 得到被编辑表项的区域
    CRect rect;
    if( GetSubItemRect(m_nItem, m_nSubItem, LVIR_LABEL, rect)==FALSE )
        return FALSE;


    // 创建编辑控件
    int style =     WS_CHILD |
                    WS_CLIPSIBLINGS |
                    WS_EX_TOOLWINDOW |




                    WS_BORDER;
    if( m_edit.Create(style, rect, this, ID_MYEDIT)==FALSE )
        return FALSE;


    // 取被编辑表项的文字
    CString txtItem = GetItemText( m_nItem, m_nSubItem );


    // 取出的文字填写到编辑控件
    m_edit.SetWindowText( txtItem );
    m_edit.SetFocus();
    m_edit.SetSel( 0, -1 );
    m_edit.ShowWindow( SW_SHOW );


    return TRUE;


}
8.     添加结束编辑函数 void EndEdit( BOOL bValidate );  主要完成替换Item内容、销毁编辑框等功能。
void CEditTable::EndEdit( BOOL bValidate )
{
    // 编辑结果是有效的,重设被编辑表项的文字




    if( bValidate )
    {
        CString txtItem;
        m_edit.GetWindowText( txtItem );
        SetItemText(m_nItem, m_nSubItem, txtItem);
    }


    // 销毁编辑窗口
    m_edit.DestroyWindow();
    m_bEditing = FALSE;
}








论坛中搜索一下,你们会发现不少类似(的)提问:我们如何编辑list control(的)条目?如何直接编辑list control...等等;list control可用来做数据库表(的)视图,十分有用.
但报表风格(的)list control只能编辑第一列,其余(的)该死(的)微软没为vc做到.它们怕VB卖不出.于是C++程序员只好DIY.主要思想是在list control中动态创建一个控件,动态移动该控件到相应位置.这些技巧早有人讨论过了,本文也是基于如上思想(的),但注重于可扩充性与使用(的)方便.
List control 这头主要是重载OnLButtonDown技巧,计算出被点中(的)条目.这里重要(的)函数是SubItemHitTest和GetSubItemRect,看msdn上有相关说明. 用户点中后,就要负责显示控件了:如果之前选中了其他们,就要验证之前(的)改动是否成功.不成功就要回到原来(的)(地)方,成功就应用修改并移到新位置.看代码:
static     const UINT IDCHAILD=3000;
void CValidateList::OnLButtonDown(UINT nFlags, CPoint point) 
{
     CListCtrl::OnLButtonDown(nFlags, point);
    LVHITTESTINFO hi;
    hi.pt = point;
    if(SubItemHitTest(&hi) != -1 )//没有点中条目就不管
    {if(m_col==-1||//-1 还没被选过
           true==(m_col+m_validate)->Validate (m_row))
       {
m_row = hi.iItem, m_col= hi.iSubItem;//m_row,m_col成
//员分别跟踪选中(的)行列
}
((m_col+m_validate))->Move (_GetRect(),m_row);
    }
}
 
WinBlast* CValidateList::SetValidate( WinBlast*in)//设置验证(的)
//控件群,in对应第一列,in+1第二列……
{
    WinBlast*ret=m_validate;
    m_validate=in;
    int counts=GetHeaderCtrl()->GetItemCount();;
    RECT rect;
     memset(&rect,0,sizeof(rect));
    for(int i=0;i<counts;++i)
         (in+i)->Create (this,rect,IDCHAILD+i,i);
    m_col=-1;//没有被选中(的)
    return ret;
}
 
 
RECT CValidateList::_GetRect()//内部使用,(得)到相应显示位置
{
    CRect ret;
GetSubItemRect(m_row,m_col,LVIR_BOUNDS,ret);
return ret;
}
 
void CValidateList::NoSelect()//置未选中状态
{
m_col=-1;//没有被选中(的)

看到了WinBlast*ret=m_validate吧.WinBlast是用来修改和验证数据(的)控件看它们(的)实现:
class WinBlast  
{
    int m_col;//跟踪列,为什么要这个?因为你们可以让一种控件对
//不同列用不同(的)验证策略
CWnd* m_win;//你们(的)控件窗口
    CListCtrl *m_parent;//用它们获(得)文本
public:
    WinBlast(){m_win=NULL;}
    ~WinBlast(){m_win->DestroyWindow();delete m_win;}
 
virtual    bool Create( CWnd* pParentWnd,
       const RECT& rect, UINT nID,
       int col)
    {
        m_col=col;m_parent=(CListCtrl *)pParentWnd;
        m_win=new CEdit;
            return  ((CEdit*)m_win)->
           Create(ES_NOHIDESEL,rect,pParentWnd,nID);  
       }
    void Move(const RECT &rect,int row)//最重要(的)函数但前面
//两个动作是必作(的),SetText为虚,你们在那做你们喜欢(的)
    {
        m_win->ShowWindow(SW_SHOW);
        m_win->MoveWindow(&rect);
        SetText(row);
    }
    virtual bool Validate(int row)//验证,虚函数.这里永远返回true
    {
        m_win->ShowWindow(SW_HIDE);
        CString set;
        m_win->GetWindowText(set);
        m_parent->SetItemText(row,m_col,set);
        return true;
    }
    virtual void SetText(int row)
    {
        m_win->SetWindowText(m_parent->GetItemText(row,m_col));
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 装修好了业主找借口不给钱怎么办 荒野行动手机换了帐号登不上怎么办 换新手机后微信头像都没有了怎么办 苹果系统维护换不了微信头像怎么办 系统通知栏不显示qq图标怎么办 快递号码写错了而且发货了怎么办 包裹遗忘在郑州东站安检口了怎么办 锁书包的锁头钥匙全掉了怎么办 平板电脑恢复出厂设置变英语怎么办 给国外银行汇款账号写错账号怎么办 顺丰快递暴力运输产品坏了怎么办 亚航订机票名字少写一个字母怎么办 如果淘宝付款七天内不发货怎么办 浪琴手表调了一下日期不走了怎么办 收件人号码写错快递柜已签收怎么办 医院名字写错了怎么办保险报销 电脑在使用中出现了英文字慕怎么办 下雨天了怎么办我好想你是什么歌 安卓手机不支持微信运动怎么办 装系统时无法跳过密匙怎么办 在msdn里下的系统没有网怎么办 w7电脑更新后系统没法激活怎么办 手机使用加速器后网速变卡怎么办 奥特曼ol分解了迪迦石像怎么办 左右棋牌游戏兑换总说系统护怎么办 四季海棠扦插以后黄叶卷叶怎么办 竹节海棠浇水多了叶子蔫了怎么办 社保停缴了里面的钱怎么办 王者荣耀英雄释放技能有延迟怎么办 买的桑拿木板颜色太深了怎么办 万一填写了奔跑吧诈骗信息该怎么办 深圳限行时段堵在路上怎么办 开车堵在路上到了限行时间怎么办 兄妹之间都不想照顾母亲我该怎么办 小孩扁体发炎睡觉呼吸声沉重怎么办 客所思pk3老驱动有杂音怎么办 手机打不开解压包密码怎么办 在香港专柜买东西柜员少给货怎么办 恶魔猎手第二神器任务没选择怎么办 电脑放久了开不了机怎么办 你在主持时说错话了怎么办