WEB开发网
开发学院软件开发VC 如何锁定 ListView 的栏目头宽度 阅读

如何锁定 ListView 的栏目头宽度

 2006-07-23 11:20:11 来源:WEB开发网   
核心提示: 为了找到答案,我们必须求助一个经常被遗忘的消息 WM_NOTIFYFORMAT,如何锁定 ListView 的栏目头宽度(2),一般控件第一次被创建时,都要向父窗口一个消息询问父窗口需要哪个版本的通知消息,为了有一个友好的用户界面,例子程序创建了一个命令菜单和界面更新处理例程,然后父窗口返

为了找到答案,我们必须求助一个经常被遗忘的消息 WM_NOTIFYFORMAT。一般控件第一次被创建时,都要向父窗口一个消息询问父窗口需要哪个版本的通知消息。然后父窗口返回 NFR_ANSI 或 NFR_UNICODE。如果父窗口不处理 WM_NOTIFYFORMAT,那么这个消息将根据父窗口或对话框本身的首选项被传递到 Windows 的 DefWindowProc 消息处理例程进行默认处理。默认为 UNICODE。因此,要知道通知消息的版本,必须处理 ListCtrl 的 WM_NOTIFYFORMAT。为了确认父窗口的返回值,你可以做一个试验便明白了。

如果你不想处理 WM_NOTIFYFORMAT 消息,那么完全可以通过双双实现 HDN_BEGINTRACKA 和 HDN_BEGINTRACKW 通知消息的处理来简化问题的解决方案,同时这种方法也更可靠和通用。此时代码将同时支持 ANSI 和 Unicode。本文附带的例子程序示范了这种方法的实现。如图一所示:

图一 锁定栏目头宽度

实现代码很简单,Header 控件发送 HDN_XXX 到父窗口(ListCtrl),在 MFC 中可以利用消息反射来处理 Header 控件的通知消息。因为“可锁定栏目头”特性本身更趋向于 Header 控件的属性,而不是 ListCtrl 的属性。如果你不用 MFC ,那么就得处理 ListCtrl 中的通知消息。例子程序使用了消息反射机制,在 Header 控件的消息映射使用 ON_NOTIFY_REFLECT,也就是该写虚拟成员函数 OnChildNotify:

BOOL CLockableHeader::OnChildNotify(UINT msg, WPARAM wp, LPARAM lp, LRESULT* pRes)
{
   NMHDR& nmh = *(NMHDR*)lp;
   if (nmh.code==HDN_BEGINTRACKW || nmg.code==HDN_BEGINTRACKA)
  return *pRes=TRUE;
   ......
}

因为 OnChildNotify 是虚函数,所以没有必要具备消息映射入口。只要实现此函数即可。在任何应用中,Header 发送的消息非此即彼,不会两者都发送。不管怎样,所发送的通知消息在到达父窗口之前都会被吃掉。也就是说,消息处理总是返回 TRUE,是否锁定栏目头的宽度通过一个标志来控制:应用程序通过 Lock 来修改标志的值。

如果锁定了头宽度,那么同时也必须禁用改变宽度的光标,这样用户界面才会有一致性,要实现这一点也很简单:

BOOL CLockableHeader::OnSetCursor( CWnd* pWnd, UINT nHit, UINT msg)
{
   return m_bLocked ? TRUE : CHeaderCtrl::OnSetCursor(pWnd, nHit, msg);
}   

如果栏目头被锁定,则 OnSetCursor 返回 TRUE,此时光标不会被重新设置,否则由 Header 控件的进行默认处理。锁定宽度后,当鼠标移到栏目头上时,Windows 显示标准的箭头光标,而不是带左右箭头光标。

从 CHeaderCtrl 派生类出来的类的使用方法与处理对话框控制一样,通过在父窗口的 OnCreate 的处理例程中进行子类化。实现细节请参考例子源代码:

// CMyView is derived from CListView
int CMyView::OnCreate(LPCREATESTRUCT lpcs)
{
 VERIFY(CListView::OnCreate(lpcs)==0);
 return m_header.SubclassDlgItem(0,this) ? 0 : -1;
}

由于 Header 控制的资源 ID = 0,所以上面的代码是行得通的。为了有一个友好的用户界面,例子程序创建了一个命令菜单和界面更新处理例程。如图一所示。

上一页  1 2 

Tags:如何 锁定 ListView

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接