📄 listctrlex.cpp
字号:
// ListCtrlEx.cpp : implementation file
//
#include "stdafx.h"
#include "Game.h"
#include "ListCtrlEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
// 设置排序的列号初始为-1,表示没有列要排序
m_nSortedCol = -1;
// 设置排序的初始方向为升序
m_bSortAscending = TRUE;
// 当前编辑的列编号
curSelCol = 0;
// 一个单元格存储单个数据的标志
isOneValueInEdit = TRUE;
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
//{{AFX_MSG_MAP(CListCtrlEx)
ON_NOTIFY(HDN_ITEMCLICKA, 0, OnItemclick)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_NOTIFY(HDN_ITEMCLICKW, 0, OnItemclick)
ON_WM_LBUTTONDBLCLK()
ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndlabeledit)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers
void CListCtrlEx::OnItemclick(NMHDR* pNMHDR, LRESULT* pResult)
{
HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;
if( phdn->iButton == 0 )
{
//鼠标左键点中表头
if( phdn->iItem == m_nSortedCol )
m_bSortAscending = !m_bSortAscending;
else
m_bSortAscending = TRUE;
m_nSortedCol = phdn->iItem;
SortTextItems( m_nSortedCol, m_bSortAscending );
m_headerCtrl.SetSortImage(m_nSortedCol, m_bSortAscending);
}
*pResult = 0;
}
void CListCtrlEx::PreSubclassWindow()
{
CListCtrl::PreSubclassWindow();
InitializeFlatHeader();
}
int CListCtrlEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
return InitializeFlatHeader();
//return 0;
}
void CListCtrlEx::OnDestroy()
{
CListCtrl::OnDestroy();
}
/*******************************************************************
功能:初始化扁平表头
参数:无
*******************************************************************/
int CListCtrlEx::InitializeFlatHeader()
{
if (!m_headerCtrl.SubclassWindow(GetDlgItem(0)->GetSafeHwnd()))
return -1;
m_headerCtrl.FlatHeader();
//SaveColumnState(_T("Settings"), _T("Control"));
return 0;
}
/*******************************************************************
功能:对选定列进行排序
参数:nCol--要排序的列号
bAscending--排序的方向,升序或降序
low--排序开始扫描的行,缺省为0
high--排序的结束行,-1表示到最后一行结束
*******************************************************************/
BOOL CListCtrlEx::SortTextItems(int nCol, BOOL bAscending, int low, int high)
{
if( nCol >= ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount() )
return FALSE;
if( high == -1 ) high = GetItemCount() - 1;
int lo = low;
int hi = high;
CString midItem;
if( hi <= lo ) return FALSE;
midItem = GetItemText( (lo+hi)/2, nCol );
//遍历要排序的所有行
while( lo <= hi )
{
//定义中间变量保存一行的所有列的文本
CStringArray rowText;
//采用二分排序法进行比较.
if( bAscending ) {
while( ( lo < high ) && ( GetItemText(lo, nCol) < midItem ) )
++lo;
}
else {
while( ( lo < high ) && ( GetItemText(lo, nCol) > midItem ) )
++lo;
}
if( bAscending ) {
while( ( hi > low ) && ( GetItemText(hi, nCol) > midItem ) )
--hi;
}
else {
while( ( hi > low ) && ( GetItemText(hi, nCol) < midItem ) )
--hi;
}
//交换两行
if( lo <= hi )
{
//进交换不等的项
if( GetItemText(lo, nCol) != GetItemText(hi, nCol))
{
//交换行
LV_ITEM lvitemlo, lvitemhi;
int nColCount =
((CHeaderCtrl*)GetDlgItem(0))->GetItemCount();
rowText.SetSize( nColCount );
int i;
for( i=0; i<nColCount; i++)
rowText[i] = GetItemText(lo, i);
lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
lvitemlo.iItem = lo;
lvitemlo.iSubItem = 0;
lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
LVIS_FOCUSED | LVIS_SELECTED |
LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
lvitemhi = lvitemlo;
lvitemhi.iItem = hi;
GetItem( &lvitemlo );
GetItem( &lvitemhi );
for( i=0; i<nColCount; i++)
SetItemText(lo, i, GetItemText(hi, i));
lvitemhi.iItem = lo;
SetItem( &lvitemhi );
for( i=0; i<nColCount; i++)
SetItemText(hi, i, rowText[i]);
lvitemlo.iItem = hi;
SetItem( &lvitemlo );
}
++lo;
--hi;
}
}
//一次交换排序未完成,继续排序
if( low < hi )
SortTextItems( nCol, bAscending , low, hi);
//一次交换排序未完成,继续排序
if( lo < high )
SortTextItems( nCol, bAscending , lo, high );
return TRUE;
}
/*******************************************************************
功能:设置列表的扩展样式
参数:dwNewStyle--列表的扩展样式
*******************************************************************/
void CListCtrlEx::SetExtendedStyle(DWORD dwNewStyle)
{
//返回列表的扩展样式
DWORD dwStyle = ::SendMessage (m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
//增加新样式
dwStyle |= dwNewStyle;
//设置新的扩展样式
::SendMessage (m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
}
/*******************************************************************
功能:鼠标左键双击,触发在位编辑
参数:系统参数
*******************************************************************/
void CListCtrlEx::OnLButtonDblClk(UINT nFlags, CPoint point)
{
int index;
int colnum;
//确保用户点击了LISTCTRL的正确行和列
if( ( index = HitTestEx( point, &colnum )) != -1 )
{
UINT flag = LVIS_FOCUSED;//LVIS_SELECTED
// 获取在位编辑的列编号
curSelCol = colnum;
//获取焦点的行,可选择在位编辑的列
if( (GetItemState( index, flag ) & flag) == flag )
{
// Add check for LVS_EDITLABELS
//if( GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS )
//保证可在位编辑列数不为空
if(m_editLines.GetSize() > 0)
{
//判断当前点击的列是否为可在位编辑列
for(int i=0 ; i<m_editLines.GetSize() ; i++)
{
//在位编辑指定的项
if( colnum == m_editLines.GetAt(i) )
EditSubLabel( index, colnum );
}
}
}
//用户仅仅选择了行,没有双击某一列,不执行在位编辑
else
SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
LVIS_SELECTED | LVIS_FOCUSED);
}
CListCtrl::OnLButtonDblClk(nFlags, point);
}
/*******************************************************************
功能:完成用户对LISTCTRL的修改
参数:系统参数
*******************************************************************/
void CListCtrlEx::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
//定义行数据的结构体,并获得用户点击的行
LV_ITEM *plvItem = &pDispInfo->item;
//在位编辑成功后,修改LISTCTRL对应项的文本
if (plvItem->pszText != NULL)
{
SetItemText(plvItem->iItem, plvItem->iSubItem,
plvItem->pszText);
}
*pResult = 0;
}
/*******************************************************************
功能:测试鼠标左键的点击事件
参数:point--鼠标点击的位置(设备坐标)
col--鼠标点击的列
*******************************************************************/
int CListCtrlEx::HitTestEx(CPoint &point, int *col)
{
int colnum = 0;
//获取用户点击的行
int row = HitTest( point, NULL );
//初始化用户点击的列为0,即第一列
if( col )
*col = 0;
//确定LISTCTRL的样式为LVS_REPORT
if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) !=
LVS_REPORT )
return row;
//获取可见行的范围,即开始行和最后一行
//本页可见的第一行
row = GetTopIndex();
//本页可见的最后一行
int bottom = row + GetCountPerPage();
if( bottom > GetItemCount() )
bottom = GetItemCount();
//获取LISTCTRL的列数总和
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount();
//在可见行中循环
for( ; row <= bottom ; row++)
{
//获取点击行的尺寸范围
CRect rect;
GetItemRect( row, &rect, LVIR_BOUNDS );
//判断鼠标点击是否发生在此行中
if( rect.PtInRect(point) )
{
//循环遍历所有列
for( colnum = 0; colnum < nColumnCount; colnum++ )
{
int colwidth = GetColumnWidth(colnum);
if( point.x >= rect.left
&& point.x <= (rect.left + colwidth ) )
{
if( col ) *col = colnum;
return row;
}
rect.left += colwidth;
}
}
}
//用户没点击任何行和列,返回此值
return -1;
}
/*******************************************************************
功能:使LISTCTRL的一项可以在位编辑
参数:nItem--在位编辑项的行
nCol--在位编辑项的列
*******************************************************************/
CFlatEdit* CListCtrlEx::EditSubLabel(int nItem, int nCol)
{
//保证在位编辑项可见
if( !EnsureVisible( nItem, TRUE ) )
return NULL;
//确定选择列合法
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount();
//确保选择列在LISTCTRL范围内,且最小的列宽为5
if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
return NULL;
//获取选择列相对于第一列的尺寸偏移
int offset = 0;
for( int i = 0; i < nCol; i++ )
offset += GetColumnWidth( i );
//计算EDIT的尺寸范围
CRect rect;
GetItemRect( nItem, &rect, LVIR_BOUNDS );
//扩展列
CRect rcClient;
//获取对用户可见的EDIT范围
GetClientRect( &rcClient );
if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
{
CSize size;
size.cx = offset + rect.left;
size.cy = 0;
//向左或右扩展EDIT尺寸
Scroll( size );
rect.left -= size.cx;
}
//获取调整尺寸后的列
LV_COLUMN lvcol;
lvcol.mask = LVCF_FMT;
GetColumn( nCol, &lvcol );
DWORD dwStyle ;
//确定LISTCTRL中的文本对齐方式和EDIT的相对位置
if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
dwStyle = ES_LEFT;
else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
dwStyle = ES_RIGHT;
else dwStyle = ES_CENTER;
//获取EDIT的真正尺寸
rect.left += offset+4;
rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
// 确保EDIT在LISTCTRL客户区内
if( rect.right > rcClient.right)
rect.right = rcClient.right;
// 设置EDIT的样式
dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
//初始化EDIT
CFlatEdit *pEdit = new CFlatEdit(nItem, nCol, GetItemText( nItem, nCol ));
// 动态创建在位编辑EDIT
pEdit->Create(dwStyle, rect, this, 1 );
// 设置EDIT的单个数据标志位
if(isOneValueInEdit == FALSE)
pEdit->SetOneValue(FALSE);
return pEdit;
}
/*******************************************************************
功能:设置LISTCTRL中可在位编辑列的集合
参数:lines--在位编辑列的集合
*******************************************************************/
void CListCtrlEx::SetEditLines(CString lines)
{
CString mid = lines , temp;
int pos1 = 0 , pos2 = 0 , num = 0 ;
while( (pos2 = mid.Find("," , pos1) ) != -1
&& pos1 < mid.GetLength() )
{
//将各可在位编辑的列记录下来
temp = mid.Mid(pos1 , pos2 - pos1);
num = atoi(temp);
m_editLines.Add(num);
pos1 = pos2 + 1;
}
}
/*******************************************************************
功能:设置一个单元格存储单个数据的标志
参数:BOOL oneValueInEdit-- 标志
*******************************************************************/
void CListCtrlEx::SetOneValueInEdit(BOOL oneValueInEdit)
{
isOneValueInEdit = oneValueInEdit;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -