MFC——LIstCtrl中嵌入Edit和Combobox控件

时间:2022-09-21 20:09:03

在MFC中经常会使用到ListCtrl控件,并且在控件中可以对单元格进行Edit的编辑或者ComboBox的编辑。实现ListCtrl中用edit和combobox编辑并数据同步,下面就是我用到的这个功能的简单实例。


为了让ListCtrol能更好的为我们所用,我们创建一个CEditListCtrl类继承自CListCtrl:


EditListCtrl.h

#pragma once
#include "ListEdit.h"
#include "ListComboBox.h"
#include "_PersistAttriMapXML.h"

#define IDC_CELL_EDIT0xffe0
#define IDC_CELL_COMBOBOX0xffe1

// CEditListCtrl

class CEditListCtrl : public CListCtrl
{
DECLARE_DYNAMIC(CEditListCtrl)

public:
CEditListCtrl();
virtual ~CEditListCtrl();

protected:
DECLARE_MESSAGE_MAP()

private:
CListEdit m_edit;
CListComboBox m_comboBox;
int m_nRow; //行
int m_nCol; //列

public:

// 当编辑完成后同步数据
void DisposeEdit(void);

//发送失效消息
void SendInvalidateMsg();

// 设置当前窗口的风格
void SetStyle(void);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnCbnSelchangeCbCellComboBox();

afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
};


EditListCtrl.cpp

// EditListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "CADIPlatform.h"
#include "EditListCtrl.h"
#include "CodeDBHelper.h"
#include "PersistXmlParser.h"

// CEditListCtrl

IMPLEMENT_DYNAMIC(CEditListCtrl, CListCtrl)

CEditListCtrl::CEditListCtrl()
{

}

CEditListCtrl::~CEditListCtrl()
{
}


BEGIN_MESSAGE_MAP(CEditListCtrl, CListCtrl)
ON_WM_LBUTTONDBLCLK()
ON_CBN_SELCHANGE(IDC_CELL_COMBOBOX, &CEditListCtrl::OnCbnSelchangeCbCellComboBox)
ON_WM_HSCROLL()
ON_WM_VSCROLL()
END_MESSAGE_MAP()



// CEditListCtrl message handlers

// 当编辑完成后同步数据
void CEditListCtrl::DisposeEdit(void)
{
int nIndex = GetSelectionMark();
//同步更新处理数据
CString sLable;
_PersistItem* pPersistItem = (_PersistItem*)GetItemData(m_nRow);
if(NULL == pPersistItem) return ;

if(0 == m_nCol) //edit控件
{
CString szLable;
m_edit.GetWindowText(szLable);
SetItemText(m_nRow,m_nCol,szLable);
pPersistItem->szPersistence = szLable;

m_edit.ShowWindow(SW_HIDE);
}
else if((1 == m_nCol) || (2 == m_nCol))
{
m_comboBox.ShowWindow(SW_HIDE);
}

}

// 设置当前窗口的风格
void CEditListCtrl::SetStyle(void)
{
LONG lStyle;
lStyle = GetWindowLong(m_hWnd,GWL_STYLE);
lStyle &= ~LVS_TYPEMASK; //清除显示方式
lStyle |= LVS_REPORT; //list模式
lStyle |= LVS_SINGLESEL; //单选
SetWindowLong(m_hWnd,GWL_STYLE,lStyle);

//扩展模式
DWORD dwStyle = GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT; //选中某行使其整行高亮
dwStyle |= LVS_EX_GRIDLINES; //网格线
SetExtendedStyle(dwStyle); //设置扩展风格
}

void CEditListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CListCtrl::OnLButtonDblClk(nFlags, point);

LVHITTESTINFO info;
info.pt = point;
info.flags = LVHT_ONITEMLABEL;

if(SubItemHitTest(&info) >= 0)
{
m_nRow = info.iItem;
m_nCol = info.iSubItem;

CRect rect;
GetSubItemRect(m_nRow,m_nCol,LVIR_LABEL,rect);

CString strValue;
strValue = GetItemText(m_nRow,m_nCol);

_PersistItem* pPersistItem = (_PersistItem*)GetItemData(m_nRow);
if(NULL == pPersistItem) return ;
//Edit单元格
if((0 == m_nCol))
{
if(pPersistItem->nFlag & 0x01)
{
MB_PROMPT(RES_LOAD_STRING(IDS_ST_MODIFIYPKATTRI_20170502_01));
return ;
}

if(NULL == m_edit)
{
//创建Edit控件
// ES_WANTRETURN 使多行编辑器接收回车键输入并换行。如果不指定该风格,按回车键会选择缺省的命令按钮,这往往会导致对话框的关闭。
m_edit.Create(WS_CHILD|WS_BORDER|ES_AUTOHSCROLL|ES_WANTRETURN|ES_LEFT,
CRect(0,0,0,0),this,IDC_CELL_EDIT);
}
m_edit.MoveWindow(rect);
m_edit.SetWindowText(strValue);
m_edit.ShowWindow(SW_SHOW);
m_edit.SetSel(0,-1);
m_edit.SetFocus();
UpdateWindow();
}
//ComboBox单元格
if((1 == m_nCol))
{
if(NULL == m_comboBox)
{
//创建Combobox控件
//CBS_DROPDOWNLIST : 下拉式组合框,但是输入框内不能进行输入
//WS_CLIPCHILDREN : 其含义就是,父窗口不对子窗口区域进行绘制。默认情况下父窗口会对子窗口背景是进行绘制的,但是如果父窗口设置了WS_CLIPCHILDREN属性,父亲窗口不在对子窗口背景绘制.
m_comboBox.Create(WS_CHILD|WS_VISIBLE|CBS_SORT|WS_BORDER|CBS_DROPDOWNLIST|WS_VSCROLL|WS_TABSTOP|CBS_AUTOHSCROLL,
CRect(0,0,0,0),this,IDC_CELL_COMBOBOX);
}
m_comboBox.MoveWindow(rect);

m_comboBox.ShowWindow(SW_SHOW);
//TODO comboBox 初始化
LoadPlmAttri();
//当前cell的值
CString strCellValue = GetItemText(m_nRow,m_nCol);
int nIndex = m_comboBox.FindStringExact(0,strCellValue);
if(CB_ERR == nIndex)
m_comboBox.SetCurSel(0); //TODO 设置为当前值的Item
else
m_comboBox.SetCurSel(nIndex);

m_comboBox.SetFocus();
UpdateWindow();
}
}
}


void CEditListCtrl::OnCbnSelchangeCbCellComboBox()
{
//同步更新处理数据
_PersistItem* pPersistItem = (_PersistItem*)GetItemData(m_nRow);
if(NULL == pPersistItem) return ;

if(1 == m_nCol) //combobox控件
{
CString szLable;
int nindex = m_comboBox.GetCurSel();
m_comboBox.GetLBText(nindex,szLable);
ATTRIFIELD* pAttriField = (ATTRIFIELD*)m_comboBox.GetItemData(nindex);
if(NULL == pAttriField)
return ;

//持久化的处理
if(0 == pAttriField->szComment.CompareNoCase(ATTRIBUTE_PERSISTENCE))
{
pPersistItem->szPersistence=pAttriField->mapPersistenceValue[ATTRIBUTE_VALUE];
SetItemText(m_nRow,m_nCol-1,pPersistItem->szPersistence);
}

pPersistItem->szUcProperty = pAttriField->szPLMToXML;
pPersistItem->szXmlOption = pAttriField->szXMLOpention;
SetItemText(m_nRow,m_nCol,pAttriField->szDetail);
m_comboBox.ShowWindow(SW_HIDE);
}
}

//发送失效消息
void CEditListCtrl::SendInvalidateMsg()
{
//Edit单元格
if((0 == m_nCol))
{

if(NULL == m_edit.m_hWnd) return ;
BOOL bShow = m_edit.IsWindowVisible();
if(bShow)
::SendMessage(m_edit.m_hWnd,WM_KILLFOCUS,(WPARAM)0,(LPARAM)0);

}
else if((1 == m_nCol)) //combobox
{
if(NULL == m_comboBox.m_hWnd) return ;

BOOL bShow = m_comboBox.IsWindowVisible();
if(bShow)
::SendMessage(m_comboBox.m_hWnd,WM_KILLFOCUS,(WPARAM)0,(LPARAM)0);
}
}

void CEditListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
SendInvalidateMsg();

CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CEditListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
SendInvalidateMsg();

CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}



CEditListCtrl 类是一个控件类在一个dialog容器中动态创建:

RECT listRect;   
GetDlgItem(IDC_ST_LISTGROUP)->GetWindowRect(&listRect); //获取List控件所在位位置,用Group占位
ScreenToClient(&listRect);

m_list.Create(WS_CHILD|WS_BORDER|LVS_SINGLESEL|LVS_REPORT,listRect,this,IDC_EDIT_LIST);
m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_UNDERLINEHOT);
m_list.ShowWindow(SW_SHOW);
RECT rect;m_list.GetClientRect(&rect);m_list.InsertColumn(0,FirstColName,LVCFMT_LEFT,rect.right/2);m_list.InsertColumn(1,SecondColName,LVCFMT_LEFT,rect.right/2);    
 
 
 

这样就动态的创建了一个listctrl

接下来 我们继续完善 ListCtrl中的Edit 和Combobox的创建

在上面CEditListCtrl 中有两个成员变量 分别是  m_edit 和m_comboBox。 这两个成员变量是我们自顶一个 Edit 和ComboBox

ListEdit.h

#pragma once// CListEditclass CListEdit : public CEdit{DECLARE_DYNAMIC(CListEdit)public:CListEdit();virtual ~CListEdit();protected:DECLARE_MESSAGE_MAP()public:afx_msg void OnKillFocus(CWnd* pNewWnd);protected:virtual void PreSubclassWindow();};

ListEdit.cpp

// ListEdit.cpp : implementation file
//

#include "stdafx.h"
#include "CADIPlatform.h"
#include "ListEdit.h"
#include "EditListCtrl.h"


// CListEdit

IMPLEMENT_DYNAMIC(CListEdit, CEdit)

CListEdit::CListEdit()
{

}

CListEdit::~CListEdit()
{
}


BEGIN_MESSAGE_MAP(CListEdit, CEdit)
ON_WM_KILLFOCUS()
END_MESSAGE_MAP()



// CListEdit message handlers



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

//ShowWindow(SW_HIDE);
CEditListCtrl* temp = (CEditListCtrl*)GetParent();
temp->DisposeEdit();

}

void CListEdit::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class

CEdit::PreSubclassWindow();
}

ListComboBox.h

#pragma once


// CListComboBox

class CListComboBox : public CComboBox
{
DECLARE_DYNAMIC(CListComboBox)

public:
CListComboBox();
virtual ~CListComboBox();

protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnCbnDropdown();
};



ListComboBox.cpp

// ListComboBox.cpp : implementation file
//

#include "stdafx.h"
#include "CADIPlatform.h"
#include "ListComboBox.h"
#include "EditListCtrl.h"


// CListComboBox

IMPLEMENT_DYNAMIC(CListComboBox, CComboBox)

CListComboBox::CListComboBox()
{

}

CListComboBox::~CListComboBox()
{
}


BEGIN_MESSAGE_MAP(CListComboBox, CComboBox)
ON_WM_KILLFOCUS()
ON_CONTROL_REFLECT(CBN_DROPDOWN, &CListComboBox::OnCbnDropdown)
END_MESSAGE_MAP()



// CListComboBox message handlers

void CListComboBox::OnKillFocus(CWnd* pNewWnd)
{
CComboBox::OnKillFocus(pNewWnd);
//ShowWindow(SW_HIDE);

CEditListCtrl *temp = (CEditListCtrl*)GetParent();
temp->DisposeEdit(); //调用父窗口的DisposeEdit()函数
}

void CListComboBox::OnCbnDropdown()
{
CClientDC dc(this);
int nTotalHeight = 0;
//获取字体信息
dc.SelectObject(GetFont());
//获取当前item的个数
int nCount = GetCount();
if(nCount <= 0) return ;
//获取字体的高度
CString strLable=_T("");
GetLBText(GetCurSel(),strLable);
int nHeight = dc.GetTextExtent(strLable).cy;

//组合框高度
CRect rect;
GetWindowRect(rect);
int height = rect.Height();

if(nCount>30)
nTotalHeight = 30*nHeight + height;
else
nTotalHeight = nCount*nHeight + height;

//设置下拉的高度
CRect rc;
GetClientRect(&rc);
SetWindowPos(NULL,0,0,rc.Width(),rc.Height()+nTotalHeight,SWP_NOZORDER|SWP_NOMOVE|SWP_SHOWWINDOW);
}


在这两个控件中  OnKillFocus 用来让控件失去焦点后的数据同步。

combobox中 CBN_DROPDOWN 消息用来处理计算下拉框的的高度。


到这里简单实例已经完成。 谢谢!