CListCtrl 报表风格,可编辑子项的完美实现

    CListCtrl要实现report风格可编辑,这个,刚开始弄得时候,是纠结比较久的,因为网上能找到的实现,一般都是自己贴个编辑框到CListCtrl上面,

    这个要说难,真的是也不难,但是比较麻烦,因为要自己修正编辑框的大小,显示隐藏编辑框等.

    但是,又有一个事实是,CListCtrl有个可编辑的属性,让你可以编辑它的第一列的,但是不能编辑其他列. 不知道设计的人为什么要这样实现.

    既然它已经可以编辑第一列了,为什么不能让它编辑所有的呢.

    网上搜了下,还是有人实现了的,按照人家提供的方法,我也实现了,这里上下代码.

    实现的原理及步骤:

 

1.先继承控件 CEdit -----. CItemEdit;

 class CItemEdit :
 public CEdit
{
public:
 CItemEdit(void);
 ~CItemEdit(void);
 DECLARE_MESSAGE_MAP()
 afx_msg void OnKillFocus(CWnd* pNewWnd);
 afx_msg void OnSetFocus(CWnd* pOldWnd);
public:
 BOOL m_bExchange;
 afx_msg void OnEnChange();
 afx_msg void OnEnterIdle(UINT nWhy, CWnd* pWho);
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos);
 void    SetWindowRect( CRect &rect );
 CRect m_WindowRect;
};

CItemEdit::CItemEdit(void)
{
 m_bExchange = FALSE;
}

CItemEdit::~CItemEdit(void)
{
}
BEGIN_MESSAGE_MAP(CItemEdit, CEdit)
//  ON_WM_KILLFOCUS()
//  ON_WM_SETFOCUS()
//  ON_CONTROL_REFLECT(EN_CHANGE, &CItemEdit::OnEnChange)
//  ON_WM_ENTERIDLE()
 ON_WM_WINDOWPOSCHANGING()
END_MESSAGE_MAP()

void CItemEdit::OnKillFocus(CWnd* pNewWnd)
{
 CEdit::OnKillFocus(pNewWnd);

 // TODO: 在此处添加消息处理程序代码
 CWnd* pParent = this->GetParent();
 ::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
 // TODO: 在此处添加消息处理程序代码
}

void CItemEdit::OnSetFocus(CWnd* pOldWnd)
{
 CEdit::OnSetFocus(pOldWnd);
 
 // TODO: 在此处添加消息处理程序代码
}

void CItemEdit::OnEnChange()
{
 // TODO:  如果该控件是 RICHEDIT 控件,则它将不会
 // 发送该通知,除非重写 CEdit::OnInitDialog()
 // 函数并调用 CRichEditCtrl().SetEventMask(),
 // 同时将 ENM_CHANGE 标志“或”运算到掩码中。

 // TODO:  在此添加控件通知处理程序代码

//1.编辑框中文字改变时给父窗口或者你期望接受编辑框中数据改变的窗口发送编辑框中数据更新的消息,接受到消息的窗口负责将数据反映到CListCtrl对应的项中
 CWnd* pParent = this->GetParent();
 ::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
 
 
}

void CItemEdit::OnEnterIdle(UINT nWhy, CWnd* pWho)
{
 CEdit::OnEnterIdle(nWhy, pWho);

 

//2.用户没有编辑时隐藏编辑框窗口
 ShowWindow( SW_HIDE );
 // TODO: 在此处添加消息处理程序代码
}

BOOL CItemEdit::PreTranslateMessage(MSG* pMsg)
{
 // TODO: 在此添加专用代码和/或调用基类

//3.编辑过程中如果用户按下回车或者esc则结束编辑,并给父窗口或者你期望接受编辑框中数据改变的窗口发送编辑框中数据更新的消息,接受到消息的窗口负责将数据反映到CListCtrl对应的项中

 if(pMsg->message == WM_KEYDOWN)
 {
  if(pMsg->wParam == VK_RETURN)
  {
   CWnd* pParent = this->GetParent();
   m_bExchange = TRUE;
   ::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
   ShowWindow( SW_HIDE );
   return TRUE;
  }
  else if(pMsg->wParam == VK_ESCAPE)
  {

   CWnd* pParent = this->GetParent();
   m_bExchange = FALSE;
   ::PostMessage(pParent->GetSafeHwnd(),WM_USER_EDIT_END,m_bExchange,0);
   ShowWindow( SW_HIDE );
   return TRUE;
  }
 }
 return CEdit::PreTranslateMessage(pMsg);
}

void CItemEdit::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{

//4.窗口位置改变时,重新设置窗口的位置为我们保存的窗口的位置 !!!重要,这里是关键,如果没有这个,那么,你会发现,不过在外面怎么

//SetWindowRect,编辑框总是在第一列!!!!!!!!!!!!!!!!!!!!!!!!!
 lpwndpos->cx = m_WindowRect.Width();
 lpwndpos->cy = m_WindowRect.Height();
 lpwndpos->x  = m_WindowRect.left;
 lpwndpos->y  = m_WindowRect.top;
 CEdit::OnWindowPosChanging(lpwndpos);

 // TODO: 在此处添加消息处理程序代码
}

void CItemEdit::SetWindowRect( CRect &rect )
{

//保存我们希望编辑框出现的位置 
   m_WindowRect = rect;
}

2.在使用CListCtrl的容器类中定义变量 CItemEdit m_Edit; 因为编辑框要一直随listctrl一直存在,因此定义成成员变量或者指针亦可,保证其生命周期就行.

3.一般是双击列表时编辑一项,响应CListCtrl的 dbclick,在其中添加如下代码

 
 LPNMITEMACTIVATE pNMListView = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
 CRect rc;
 CListCtrl &m_list = GetListCtrl();

 CPoint pt( pNMListView->ptAction );

 m_row = HitTextEx( pt , &m_column );    //这里是根据点击位置取得双击的行,列索引
  
   m_list.GetSubItemRect(m_row, m_column,LVIR_BOUNDS,rc);//取得子项的矩形
   rc.left+=3;
   rc.top+=2;
   rc.right+=3;
   rc.bottom+=2;

   m_pEdit = m_list.EditLabel( m_row );   //取得CListCtrl自带的编辑框
   m_edit.SubclassWindow( m_pEdit->GetSafeHwnd() );  //用我们子类化的类,子类华这个自带的编辑框类
   m_edit.SetWindowRect( rc );                                                //将窗口移至对应项的窗口位置
  // m_pEdit->MoveWindow( rc );
   CString strInfo = m_list.GetItemText( m_row , m_column );  //取得对应项的内容设置到编辑框中.,
   m_pEdit->SetWindowText( strInfo );

 // TODO: 在此添加控件通知处理程序代码
 *pResult = 0;

 

4. HitTestEx的实现

int HitTextEx( CPoint &point , int *col )const
{
 int colnum = 0;
 CListCtrl &listCtrl = GetListCtrl();
 int row = listCtrl.HitTest( point, NULL );

 if( col ) *col = 0;

 // Make sure that the CListCtrlis in LVS_REPORT
 if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
  return row;

 // Get the top and bottom row visible
 row = listCtrl.GetTopIndex();
 int bottom = row + listCtrl.GetCountPerPage();
 if( bottom > listCtrl.GetItemCount() )
  bottom = listCtrl.GetItemCount();

 // Get the number of columns
 CHeaderCtrl* pHeader = (CHeaderCtrl*)listCtrl.GetDlgItem(0);
 int nColumnCount = pHeader->GetItemCount();

 // Loop through the visible rows
 for( ;row <=bottom;row++)
 {
  // Get bounding rect of item and check whether point falls in it.
  CRect rect;
  listCtrl.GetItemRect( row, &rect, LVIR_BOUNDS );
  if( rect.PtInRect(point) )
  {
   // Now find the column
   for( colnum = 0; colnum < nColumnCount; colnum++ )
   {
    int colwidth = listCtrl.GetColumnWidth(colnum);
    if( point.x >= rect.left
     && point.x <= (rect.left + colwidth ) )
    {
     if( col ) *col = colnum;
     return row;
    }
    rect.left += colwidth;
   }
  }
 }

 return -1;
}

 

5.接收处理CItemEdit发送回来的 Edit_end消息

:OnLvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult)
{
 NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
 // TODO: 在此添加控件通知处理程序代码
 CListCtrl &listCtrl = GetListCtrl();

 listCtrl.SetItemText( m_row , m_column , pDispInfo->item.pszText );

 if( ::IsWindow( m_edit.GetSafeHwnd()  ) )
 m_edit.UnsubclassWindow();
 
 m_bEditing = FALSE;
 

 m_pEdit = NULL;
 *pResult = 0;
}

 

6. 相信你以大功告成了,不用谢我.我也只是参照别人的基础上,把我的代码贴上来
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值