ClistCtrl 列宽问题

Remark:Clistctrl 改用CustomDraw机制,ListCtrl的样式就不能用Owner Draw Fixed;如果用了Owner Draw Fixed,就必须继承DrawItem成员寒暑,并且不能调用基类的DrawItem成员,因为:
void CListCtrl::DrawItem(LPDRAWITEMSTRUCT)
{
ASSERT(FALSE);
}

用了CustomDraw,应该在ListCtrl控件的父类,也就是Dialog中响应OnCustomDraw(),而不是再CListCtrl的继承类中响应。客户定制绘图(Custom Draw)和自绘(Owner Draw)是不同的概念。

 

自动调整列宽1

自动调整CListCtrl 列宽

void CPrintsysDlg::AdjustColumnWidth()
{
//SetRedraw(FALSE);
int nColumnCount = GetColumnCount();

for (int i = 0; i < nColumnCount; i++)
{
m_list.SetColumnWidth(i, LVSCW_AUTOSIZE);
int nColumnWidth =m_list. GetColumnWidth(i);
m_list.SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
int nHeaderWidth = m_list.GetColumnWidth(i); 
m_list.SetColumnWidth(i, max(nColumnWidth, nHeaderWidth));
}
// SetRedraw(TRUE);
} 
int CPrintsysDlg::GetColumnCount()
{
CHeaderCtrl* pHeaderCtrl =m_list. GetHeaderCtrl();
return (pHeaderCtrl->GetItemCount());
}


 

自动调整列宽2

 

void CListCtrlEx::AutoSizeColumns(int col /*=-1*/,BOOL bFitWidth/*=FALSE*/) 
{  
	// Call this after your list control is filled 
	CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
	int ColumnCount =  pHeaderCtrl->GetItemCount();
	if(!GetHeaderCtrl())return; 
	ShowWindow(SW_HIDE);//避免闪烁
	SetRedraw(FALSE);  
	if(!bFitWidth)//如果不自动调整最后一列宽度,使得总列宽等于控件宽度,
		InsertColumn(ColumnCount,""); 
	int mincol = col < 0 ? 0 : col;  
	int maxcol = col < 0 ? ColumnCount-1 : col; 

	for (col = mincol; col <= maxcol; col++) { 
		SetColumnWidth(col,LVSCW_AUTOSIZE); 
		int wc1 = GetColumnWidth(col);  
		SetColumnWidth(col,LVSCW_AUTOSIZE_USEHEADER); 
		int wc2 = GetColumnWidth(col); 
		int iFrom=GetTopIndex();  
		int nCountPerpage=GetCountPerPage(); 
		if(nCountPerpage<=0)  
			nCountPerpage=GetItemCount(); 
		int iTo=iFrom+nCountPerpage; 
		int nImgWidth=0; 
		int iIndent=0; 
		LVITEM li;  
		li.mask=LVIF_IMAGE|LVIF_INDENT; 
		IMAGEINFO ImageInfo;  
		for(int iItem=iFrom;iItem<iTo;iItem++){ 
			li.iItem=iItem; 
			GetItem(&li);  
			iIndent=max(li.iIndent,iIndent); 
			if(li.iImage!=-1){  
				CImageList* pImageList=GetImageList(LVSIL_SMALL); 
				if(pImageList->GetSafeHandle()){  
					pImageList->GetImageInfo(li.iImage,&ImageInfo);  
					nImgWidth=max(nImgWidth,ImageInfo.rcImage.right-ImageInfo.rcImage.left); 
				}  
			} 
		}  
		int wc = max(20,max(wc1,wc2)); 
		if(col==0)  
			wc+=nImgWidth*(iIndent+1); 
		else  
			wc+=nImgWidth;  
		SetColumnWidth(col,wc); 
	}  
	if(!bFitWidth)  
		DeleteColumn(ColumnCount-1); 
	SetRedraw(TRUE); 
	ShowWindow(SW_SHOW); 
}  


禁止列宽拖动

通过重写虚函数OnNotify实现。

类视图加入OnNotify:

//头文件中   
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); 

//函数定义
//禁止List控件列与列之间的拖拉
BOOL CListCtrlEx::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	HD_NOTIFY     *pHDN   =   (HD_NOTIFY*)lParam; 
	switch(((NMHDR*)lParam)->code)
	{
	case HDN_BEGINTRACKW://拖动
	case HDN_BEGINTRACKA:
	case HDN_DIVIDERDBLCLICK://双击
	if   (pHDN->iItem  == Col)  // Col—设定为自己不想改变的列值,比如Col=0,就是第1列
	{
		*pResult = TRUE;
		return TRUE;
	}
	break;
	}
	return CListCtrl::OnNotify(wParam, lParam, pResult);
}
 

固定标题列宽,禁止拖动(Ini ListCtril中调用):

CHeaderCtrl* pHeaderCtrl = (CHeaderCtrl*)m_ListCtrl.GetHeaderCtrl();   
pHeaderCtrl->EnableWindow( FALSE ) ;

禁止点击列(Ini ListCtril中调用):

BOOL CListCtrlEx::PreTranslateMessage(MSG* pMsg)
{
 if(pMsg->message==WM_LBUTTONDOWN || pMsg->message==WM_LBUTTONUP)
 {
  CHeaderCtrl* pHead;
  pHead=GetHeaderCtrl();
  if(pMsg->hwnd==pHead->m_hWnd){
   //return TRUE;   //无法点击列
  }
 }
 return CListCtrl::PreTranslateMessage(pMsg);
}


 

把ListCtrl最后一列自动调整大小;并随对话框改变而改变  

建立工程AutoListCtrl
给 CAutolistCtlDlg添加如下几个函数,在OnInitDialog()中调用SetList();
private:
 void SetList();
 void SetListColumn();
 void SetListText();
 void ReSizeList();

void CAutolistCtlDlg::SetList()
{
 SetListColumn();
 SetListText();
 ReSizeList();
}

void CAutolistCtlDlg::SetListColumn()//列表头
{
 CString strColumn;
 for (int i = 0; i < 3; i++)
 {
  strColumn.Format(_T("Column(%d)"), i);
  m_xList.InsertColumn(i, strColumn,LVCFMT_LEFT, 100);
 }
}

void CAutolistCtlDlg::SetListText()
{
 CString strListText;
 for (int i = 0; i < 3; i++)
  for (int j = 0; j < 10; j++)
  {
   strListText.Format(_T("Item[%d][%d]"), j, i);
   if (0 == i)
    m_xList.InsertItem(j, strListText);//第一列
   else
    m_xList.SetItemText(j, i, strListText);//后面几列
  }
}

void CAutolistCtlDlg::ReSizeList()
{
 CRect rect;
 GetClientRect(&rect);//wnd的
 m_xList.MoveWindow(5, 5, rect.Width() - 10, rect.Height() - 10);
}
void CAutolistCtlDlg::OnSize(UINT nType, int cx, int cy)//对话框对应消息ON_WM_SIZE的函数
{
 CDialog::OnSize(nType, cx, cy);
 
 if (IsWindow(m_xList.m_hWnd))//会在InitDialog之前执行一次,这个时候listctrl还没被创建
 {
  m_xList.MoveWindow(5, 5, cx - 1, cy -10);
  //m_xList.AutoColumn();
 }
}

/*Onsize中的代码使ListCtrl随对话框的缩放而缩放,要使对话框有缩放功能,必须在对话框的Border属性中选择Resizing*/

接下来要让listcrl的最后一列自动对齐(填满)
新建一个MFC类继承于CListCtrl
class CAutoColumnList : public CListCtrl
添加成员函数
public:
 void AutoColumn();
private:
 void OnSize(UINT nType, int cx, int cy);//List的ON_WM_SIZE()对应的消息函数
//.cpp
BEGIN_MESSAGE_MAP(CAutoColumnList, CListCtrl)
 ON_WM_SIZE()
END_MESSAGE_MAP()
/*1.ON_WM_SIZE()是MFC自带消息,其消息函数一定对应void OnSize(UINT nType, int cx, int cy)形式。
但我们仍然要自己把OnSize声明一下
2.如果是自定义消息,则要这么写:
BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
 ON_WM_SIZE()
   ON_MESSAGE(WM_RESIZEME,OnResizeMe)
END_MESSAGE_MAP()*/

void CAutoColumnList::OnSize(UINT nType, int cx, int cy)
{
 CListCtrl::OnSize(nType, cx, cy);
 AutoColumn();
}
// CAutoColumnList message handlers

void CAutoColumnList::AutoColumn()//自动调节最后一列
{
 CRect xRect;
 int nLastColumnWidth = 0;
 int nColumnNum = 0;

 GetClientRect(&xRect);//OleControl的
 nLastColumnWidth = xRect.Width();
 nColumnNum = GetHeaderCtrl()->GetItemCount();
 
 for (int i = 0; i < nColumnNum - 1; i++)
  nLastColumnWidth = nLastColumnWidth - GetColumnWidth(i);
 SetColumnWidth(nColumnNum - 1, nLastColumnWidth);
}

 

最后,要记得把ListCtrl的变量m_xList类型改为CAutoColumnList
到此为止,程序可以运行了,但我们会问,为什么要为ListCtl设置一个消息函数OnSize,而不直接在Dlg的OnSize里面调用m_xList.AutoColumn()呢?
下面来看一下CAutolistCtlDlg::OnSize,  CAutolistCtlDlg::OnInitDialog(),

CAutoColumnList::OnSize这三个函数在程序刚启动时的调用顺序:
1.首先调用CAutolistCtlDlg::OnSize
 知道为什么要:
if (IsWindow(m_xList.m_hWnd))//会在InitDialog之前执行一次,这个时候listctrl还没被创建
 {
  m_xList.MoveWindow(5, 5, cx - 1, cy -10);
  //m_xList.AutoColumn();
 }
判断一下了吧?这个时候listctrl还没生成,使用它当然会出错。当然,有了此条件语句,在其内部的
m_xList.AutoColumn()想执行也执行不了了。

2.再调用CAutolistCtlDlg::OnInitDialog(),这个时候SetList()被调用了。
3.最后调用CAutoColumnList::OnSize,因为listCtrl已经建立,调用AutoColumn()自然可以成功调整列。

所以如果把AutoColumn()放在CAutolistCtlDlg::OnSize中而不是CAutoColumnList::OnSize中,刚启动程

序时是不会对齐的,直到resize一下dlg,再次执行CAutolistCtlDlg::OnSize,则条件语句中的东西才能被执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值