VC 界面窗口,靜態分割后如何鎖定分隔條或限制分隔條的移動范圍
來北航做畢業設計已經有半個月了,由于實驗室中,項目組用的是VC,昨天剛好遇到一個細節問題:大家都知道,VC中可以動態或者靜態的分割窗口(關于這點許多地方說的已經很清楚了,這里不做討論)但是實際上,很多時候我們想要的只是靜態的分割出窗口,并不想讓別人移動改變這個比例,或者是需要限定某個分割出的窗口的范圍(比如是小到多少之后就不能再變小了),關于這個問題許多書上都沒有解釋(PS:莫非是覺得太簡單了,直接忽略么?orz...)本人研究了一下, 關于鎖定分割大致有兩種方法,而如何限制移動范圍也可已在此基礎上加,特此總結如下:
鎖定的話,其中一種方法是直接截獲一個消息,我們知道,其實 CsplitterWnd 是從CWnd 派生出來的,所以其實很容易截獲Window的消息,在這里我們應該關注的其實僅僅只有一個消息WM_NCHITTEST ,其作用大致就是當你的鼠標在這個劃分出的區域中移動時為CWnd捕捉你的鼠標輸入的,所以,換言之,如果我們截獲了這個消息,直接返回為HTNOWHERE(參考MSDN),那么當你的鼠標停留在Splitter上時就不會出現任何反應,從而鎖定的目的就達到了
另一種是重載:OnLButtonDown(UINT nFlags, CPoint point),OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 以及OnMouseMove(UINT nFlags, CPoint point)幾個函數,前兩個函數的重載也可以達到鎖定的效果,第三個函數也就是OnMouseMove()的重載則是為了限定移動的范圍(這種情況可能需要的更多一些)下面貼上這兩種方法的代碼:
兩種方法有一個共同點就是需要自己從CSplitterWnd類中派生一個自己的類就叫 MySplitterWnd 好了,先采用第一種方法,來鎖定,MySplitterWnd.h中代碼如下:
#if !defined(AFX_MYSPLITTERWND_H__A2E77A4F_BB34_4622_8178_ED5FB394208E__INCLUDED_)
#define AFX_MYSPLITTERWND_H__A2E77A4F_BB34_4622_8178_ED5FB394208E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MySplitterWnd.h : header file
//

/**//////////////////////////////////////////////////////////////////////////////
// MySplitterWnd frame with splitter
#ifndef __AFXEXT_H__
#include <afxext.h>
#endif
class MySplitterWnd : public CSplitterWnd

{
DECLARE_DYNCREATE(MySplitterWnd)
protected:
// protected constructor used by dynamic creation
// Attributes
protected:
CSplitterWnd m_wndSplitter;
public:
MySplitterWnd(); 
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(MySplitterWnd)
protected:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
afx_msg UINT OnNcHitTest(CPoint point); //新加的
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~MySplitterWnd();
// Generated message map functions
//{{AFX_MSG(MySplitterWnd)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

/**//////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MYSPLITTERWND_H__A2E77A4F_BB34_4622_8178_ED5FB394208E__INCLUDED_)
其中關鍵的語句就是 加一句 afx_msg UINT OnNcHitTest(CPoint point)的定義,然后再在MySplitterWnd.cpp具體實現這個函數,如下
// MySplitterWnd.cpp : implementation file
//
#include "stdafx.h"
#include "GL.h"
#include "MySplitterWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/**//////////////////////////////////////////////////////////////////////////////
// MySplitterWnd
IMPLEMENT_DYNCREATE(MySplitterWnd, CSplitterWnd)
MySplitterWnd::MySplitterWnd()

{
}
MySplitterWnd::~MySplitterWnd()

{
}

BOOL MySplitterWnd::OnCreateClient(LPCREATESTRUCT /**//*lpcs*/, CCreateContext* pContext)

{
return m_wndSplitter.Create(this,
2, 2, // TODO: adjust the number of rows, columns
CSize(10, 10), // TODO: adjust the minimum pane size
pContext);
}

afx_msg UINT MySplitterWnd::OnNcHitTest(CPoint /**//*point*/)

{
return HTNOWHERE;
}


/**//*BEGIN_MESSAGE_MAP(MySplitterWnd, CSplitterWnd)
//{{AFX_MSG_MAP(MySplitterWnd)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()*/

BEGIN_MESSAGE_MAP(MySplitterWnd, CSplitterWnd)
ON_WM_NCHITTEST()
END_MESSAGE_MAP()


/**//////////////////////////////////////////////////////////////////////////////
// MySplitterWnd message handlers
可以看到,具體實現就一句話,return HTNOWHERE。現在就OK了,我的表述已經盡可能清楚了,如果實在不理解也沒關系,你們可以直接將上面的.h和.cpp直接復制過去,直接加入到你的工程中,到時候用的時候直接 定義用 MySplitterWnd這個類定義 自己的變量,如 MySplitterWnd XXX(自己隨便取名)
下面介紹另一種方法,也是同上面一樣需要自己建立一個類,還是叫MySplitterWnd好了,基類還是CSplitterWnd
然后 在MySplitterWnd.h中添加如下代碼(位置 和添加OnNcHitTest(...)函數一樣)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
在MySplitterWnd.cpp中添加三個函數的具體實現代碼如下:
void MySplitterWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
// 直接返回,不處理
return;
}
BOOL MySplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// 當光標進入分割窗口時,不允許改變樣子,不處理
return FALSE;
}
void MySplitterWnd::OnMouseMove(UINT nFlags, CPoint point)
{
//將CSplitter類的處理改為由CWnd處理
//CSplitterWnd::OnMouseMove(nFlags, point);
if(point.x<250||point.x>500) CWnd::OnMouseMove(nFlags, point);
else CSplitterWnd::OnMouseMove(nFlags, point);
}
好了,其實到了這里還沒有完,剛說到鎖定的問題,大家可以發現如果三個函數這樣子寫你的分隔條直接不能動了,和剛才的截取消息的鎖定效果一摸一樣,但是關于第三個函數OnMouseMove()的實際作用其實是限定范圍,if(point.x<250||point.x>500) CWnd::OnMouseMove(nFlags, point);
else CSplitterWnd::OnMouseMove(nFlags, point); 這兩句的意思是說將移動范圍鎖定在250和500之間(這個數值大家可以隨便設置),為了要使得這個函數生效,大家可以把前面兩個也就是OnLButtonDown()和OnSetCursor()屏蔽掉,只留下第三個OnMouseMove()就可以達到限制范圍的效果了,當然只屏蔽掉OnLButtonDown()函數也是可以的,因為OnSetCursor()函數只是改變光標樣子用的,(鎖定的另一個方法其實就是只用前面兩個,既屏蔽掉OnMouseMove(),這個函數,大家可以自己試試,分別屏蔽看會出現什么效果)
MySplitterWnd.h和MySplitterWnd.cpp分別如下:
MySplitterWnd.h:
#if !defined(AFX_MYSPLITTERWND_H__7AA280DC_82F5_4FF5_95A6_036C8A20B50D__INCLUDED_)
#define AFX_MYSPLITTERWND_H__7AA280DC_82F5_4FF5_95A6_036C8A20B50D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MySplitterWnd.h : header file
//

/**//////////////////////////////////////////////////////////////////////////////
// MySplitterWnd frame with splitter
#ifndef __AFXEXT_H__
#include <afxext.h>
#endif
class MySplitterWnd : public CSplitterWnd

{
public:
MySplitterWnd();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(MySplitterWnd)


//}}AFX_VIRTUAL
// Implementation
public:
virtual ~MySplitterWnd();

DECLARE_DYNCREATE(MySplitterWnd)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point); //新加的
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); //新加的
afx_msg void OnMouseMove(UINT nFlags, CPoint point); //新加的
DECLARE_MESSAGE_MAP() //后加的

};

/**//////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MYSPLITTERWND_H__7AA280DC_82F5_4FF5_95A6_036C8A20B50D__INCLUDED_)
MySplitterWnd.cpp:
// MySplitterWnd.cpp : implementation file
//
#include "stdafx.h"
#include "GL.h"
#include "MySplitterWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/**//////////////////////////////////////////////////////////////////////////////
// MySplitterWnd

IMPLEMENT_DYNCREATE(MySplitterWnd, CSplitterWnd)

BEGIN_MESSAGE_MAP(MySplitterWnd, CSplitterWnd)
//ON_WM_LBUTTONDOWN()
//ON_WM_SETCURSOR()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()



MySplitterWnd::MySplitterWnd()

{
}
MySplitterWnd::~MySplitterWnd()

{
}

/**//*void MySplitterWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
// 直接返回,不處理
return;
}
BOOL MySplitterWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// 當光標進入分割窗口時,不允許改變樣子,不處理
return FALSE;
}*/
void MySplitterWnd::OnMouseMove(UINT nFlags, CPoint point)

{
//將CSplitter類的處理改為由CWnd處理
//CSplitterWnd::OnMouseMove(nFlags, point); 
if(point.x<250||point.x>500) CWnd::OnMouseMove(nFlags, point);
else CSplitterWnd::OnMouseMove(nFlags, point); 
}




/**//*
BEGIN_MESSAGE_MAP(MySplitterWnd, CSplitterWnd)
//{{AFX_MSG_MAP(MySplitterWnd)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()*/

/**//////////////////////////////////////////////////////////////////////////////
// MySplitterWnd message handlers
說的可能有些不清楚,不清楚的也沒關系,可以直接將上面的MySplitterWnd.h和MySplitterWnd.cpp導入到自己的工程中,直接用就行了,將你要鎖定或者限制移動范圍的分割區域用MySplitterWnd定義,不做限制,鎖定的區域用CSplitterWnd類定義,這樣子就可以做到有選擇的限制鎖定某幾個分割區域的效果.
posted on 2010-03-29 15:09 蝸牛也Coding 閱讀(4376) 評論(5) 編輯 收藏 引用

