CSplitterWndEx:指示分隔器窗口焦点和自动拆分






4.96/5 (16投票s)
2000 年 1 月 14 日

290040

6736
一个教程,展示了如何自动拆分视图,以及如何指示哪个视图具有焦点
引言
我正在使用 MFC 和文档/视图框架开发一个 CAD/CAM 应用程序。在此应用程序中,C<MyProject>View
包含一个带有 3D 对象的 3D 视图。在 CAD/CAM 行业,我们需要 3D 窗口的不同视点,因此我实现了一个自动拆分功能,该功能将 3D 视图平铺成 4 个窗格:前面、顶部、左面和轴测图。
不幸的是,我无法提供 CAD/CAM 应用程序的示例(因为它使用了第三方库),但您会找到一个简单的 MFC 项目,展示了自动拆分功能和焦点。
本教程解释了如何将焦点设置在拆分视图的当前窗格上,以及如何自动拆分视图(无需提供 splitterbar
的位置)。
注意:关于焦点,我使用的是在互联网或书籍中找到的代码,但我记不清是在哪里找到的了。如果您编写了此代码,请联系我,我会为您注明。
1. 创建项目
您可以使用 MFC 应用程序向导生成项目代码
- 打开 Visual C++。
- 选择文件 | 新建 | MFCAppWizard (EXE)。
- 为名称(
MyProj
)和路径命名。 - 保留默认选项(直接完成)。
您的项目已完成;您可以编译并运行它。
如果您运行它,您会在“窗口”菜单中看到,没有拆分选项。
2. 添加分隔条
为此,您应该使用组件库
- 选择项目 | 添加到项目 | 组件和控件。
- 进入 Visual C++ 组件,选择
SplitterBar
。 - 选择“全部”/“确定”并关闭。
现在,如果您查看 CChildFrame
类,您会看到 OnCreateClient
方法,该方法创建了 SplitterWnd
。打开资源视图,在菜单 IDR_MYPROJTYPE
中,在 *窗口* 下添加条目 &拆分
,ID 为 ID_WINDOW_SPLIT
。
构建可执行文件,并测试“拆分
”功能(应该可以工作)。
3. 创建一个继承自 CSplitterWnd 的新类
- 选择插入 | 新建类
- 类类型:MFC
- 名称:
CSplitterWndEx
- 基类:通用
CWnd
- 编辑文件 SplitterWnd.h 和 SplitterWnd.cpp,并将所有
CWnd
对象替换为CSplitterWnd
对象 - 编辑 ChildFrm.h,在包含文件的顶部插入
#include "SplitterWndEx.h"
,然后替换CSplitterWnd m_wndSplitter;
用
CSplitterWndEx m_wndSplitter;
现在,您有了一个新的类可以使用。
4. 设置焦点
向 CSplitterWndEx
添加以下 2 个 public
方法
void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg);
void RefreshSplitBars(void);
void CSplitterWndEx::OnDrawSplitter(CDC* pDC,
ESplitType nType, const CRect& rectArg)
{
int x_ActivePane, y_ActivePane;
COLORREF hilightcolor = RGB(255,255,0);
GetActivePane(x_ActivePane, y_ActivePane);
if( ((GetRowCount()>1) ||(GetColumnCount()>1))
&& (nType == splitBorder))
{
int pRow = 0;
int pCol = 0;
if(rectArg.top)
{
pRow = 1;
}
if(rectArg.left)
{
pCol = 1;
}
if((pCol == y_ActivePane) && (pRow == x_ActivePane))
{
if (pDC == NULL)
{
RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
return;
}
ASSERT_VALID(pDC);
CRect rect = rectArg;pDC->Draw3dRect(rect,
hilightcolor, hilightcolor);
int dx = -GetSystemMetrics(SM_CXBORDER);
int dy = -GetSystemMetrics(SM_CYBORDER);
rect.InflateRect(dx,dy);
pDC->Draw3dRect(rect, hilightcolor, hilightcolor);
return;
}
}
CSplitterWnd::OnDrawSplitter(pDC,nType,rectArg);
}
此方法会在 ActivePane
周围绘制一个额外的 Rectangle
,颜色为 hilightcolor
。
注意:您可以设置 2 种颜色(请参阅 Draw3dRect
的帮助)。
void CSplitterWndEx::RefreshSplitBars(void)
{
CRect rectInside;
GetInsideRect(rectInside);
DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
}
此方法调用刷新分隔条。
您拥有绘制焦点窗口的所有方法。您只需要调用它们
- 使用类向导,为
CMyProjView
添加WM_KILLFOCUS
和WM_SETFOCUS
消息的句柄。 - 在这两个方法中,都写以下一行
((CChildFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();
- 在 CMyProjView.cpp 中,添加包含:
#include "ChildFrm.h"
- 转到
CChildFrame
包含文件,并更改访问权限CSplitterWndEx m_wndSplitter;
从protected
到public
。 - 构建项目并运行它。
在“窗口”菜单中选择*拆分*。单击一个窗格时,会绘制一个黄色边框。它显示哪个窗格具有焦点。
自动拆分
自动拆分是无需鼠标事件即可将视图拆分成 4 个视图的功能。这意味着 CView
被拆分成 4 个视图,其中 newWidth = oldWidth / 2
和 newHeight = oldHeight / 2
。
首先,向 CSplitterWnd
类添加两个布尔值
Public:
bool m_bSplittingDone;
protected :
bool m_bIsAutomaticSplit;
在构造函数中,初始化这些成员
CSplitterWndEx::CSplitterWndEx()
{
m_bIsAutomaticSplit = false;
m_bSplittingDone = false;
}
要调用拆分函数,您需要使用 CSplitterWnd::DoKeyboardSplit();
。
我们向类写入 4 个新方法
public:
BOOL DoAutomaticSplit(); // new method
BOOL DoKeyboardSplit(); // overload the CSplitterWnd::DoKeyboardSplit();
protected:
void StartTracking(int ht); // overload the CSplitterWnd::StartTracking
void StopTracking(BOOL bAccept); // overload the CSplitterWnd::StopTracking
void CSplitterWndEx::StartTracking(int ht)
{
//save the current cursor ...
HCURSOR theCurrentCursor = GetCursor();
CSplitterWnd::StartTracking(ht);
if ( m_bIsAutomaticSplit )
{
//...and restore it immediately if in AutomaticSplit mode
SetCursor(theCurrentCursor);
}
}
void CSplitterWndEx::StopTracking(BOOL bAccept)
{
CSplitterWnd::StopTracking(bAccept);
//now the is splitting done
m_bIsAutomaticSplit = false;
m_bSplittingDone = true;
}
BOOL CSplitterWndEx::DoAutomaticSplit()
{
//save the current mouse position
POINT theInitialMousePosition;
GetCursorPos(&theInitialMousePosition);
//set the splitting done to false ( of course )
m_bSplittingDone = false;
//and automatic to true
m_bIsAutomaticSplit = true;
//do the split
BOOL RetVal = CSplitterWnd::DoKeyboardSplit();
//restore immediately the old mouse position
SetCursorPos(theInitialMousePosition.x,theInitialMousePosition.y);
return RetVal;
}
BOOL CSplitterWndEx::DoKeyboardSplit()
{
m_bSplittingDone = false;
m_bIsAutomaticSplit = false;
return CSplitterWnd::DoKeyboardSplit();
}
我们还需要重载 OnMouseMove
事件
void CSplitterWndEx::OnMouseMove(UINT nFlags, CPoint pt)
{
if ( m_bIsAutomaticSplit )
{
//if AutomaticSplit mode : We are not able
//to choose the position of the splitters
// -> Exiting to next step
StopTracking(TRUE);
return;
}
CSplitterWnd::OnMouseMove(nFlags,pt);
}
注意,您将需要调用 DoAutomaticSplit
方法。您可以在 CChildFrame
类中调用它
void CChildFrame::AutomaticSplit()
{
// set the timer ( just a trick make an action once the splitting is done )
KillTimer(1); // Destroy the old timer
SetTimer(1, 10 , NULL); // Creates a new timer (index = 1 ; time = 10ms)
m_wndSplitter.DoAutomaticSplit();
}
void CChildFrame::OnTimer(UINT nIDEvent)
{
if ( m_wndSplitter.m_bSplittingDone ) // if the splitting is done
{
KillTimer(1); // kill the timer
// ( just a trick make an action once the splitting is done )
//loop on the row & columns
int nbRow = m_wndSplitter.GetRowCount();
int nbCol = m_wndSplitter.GetColumnCount();
for ( int r = 0; r < nbRow ; r++ )
{
for ( int c=0 ; c < nbCol ; c++ )
{
CMyProjView* theView = (CMyProjView*)m_wndSplitter.GetPane(r,c);
if ( r==0 && c== 0)
//top-lefttheView->DoSomething(RGB(255,0,0));
else if ( r==0 && c== 1)
//top-righttheView->DoSomething(RGB(0,255,0));
else if ( r==1 && c== 0)
//bottom-lefttheView->DoSomething(RGB(0,0,255));
else if ( r==1 && c== 1)
//bottom-righttheView->DoSomething(RGB(255,255,0));
}
}
}
}
这里,我使用一个定时器技巧在拆分完成后执行一些操作。
现在,您可以调用 CChildFrame::AutomaticSplit()
方法来拆分 CView
。
例如,使用类向导,您可以在*窗口*菜单中创建一个新条目,并添加对 AutomaticSplit
的调用
void CChildFrame::OnWindowAutomaticsplit()
{
AutomaticSplit();
}
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。