MFC框架中的视图分割与焦点设置

在CAD/CAM行业中,经常需要对3D视图进行不同角度的观察。本文将介绍如何在MFC框架中实现视图的自动分割以及如何设置当前视图的焦点。虽然无法提供CAD/CAM应用程序的示例代码(因为它使用了第三方库),但会提供一个简单的MFC项目,展示自动分割功能和焦点设置的基本方法。

创建项目

使用MFC应用程序向导生成项目代码:

  1. 打开Visual C++。
  2. 选择“文件”|“新建”|“MFC应用程序向导(.exe)”。
  3. 输入项目名称(例如"MyProj")和路径。
  4. 保持默认选项,直接完成。

编译并运行项目。如果运行项目,可以看到在窗口菜单中没有分割选项。

添加分割条

要添加分割条,应使用组件库:

  1. 选择“项目”|“添加到项目”|“组件和控件”。
  2. 进入Visual C++组件,选择“SplitterBar”。
  3. 选择“Both/OK”并关闭。

现在,如果查看CChildFrame类,将看到OnCreateClient方法,它创建了SplitterWnd。打开资源视图,在菜单IDR_MYPROJTYPE下添加“&Split”项,ID为ID_WINDOW_SPLIT。构建可执行文件,并测试"Split"功能(它应该可以工作)。

创建新的类继承自CSplitterWnd

选择“插入”|“新类”:

  1. 类类型:MFC
  2. 名称:CSplitterWndEx。
  3. 基类:Generic CWnd。

编辑SplitterWnd.h和SplitterWnd.cpp文件,将所有CWnd对象替换为CSplitterWnd对象。编辑ChildFrm.h,在包含文件的顶部插入#include "SplitterWndEx.h",并将CSplitterWnd m_wndSplitter替换为CSplitterWndEx m_wndSplitter。现在,有了一个新的类来工作。

设置焦点

向CSplitterWndEx添加以下两个public方法:

void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg); void RefreshSplitBars(void);

OnDrawSplitter方法绘制一个额外的矩形围绕ActivePane,使用hilightcolor颜色。RefreshSplitBars方法调用刷新splitbars。已经有了所有绘制焦点窗口的方法。只需要调用它们:

  1. 使用类向导,为CMyProjView添加WM_KILLFOCUS和WM_SETFOCUS消息的处理程序。
  2. 在两个方法中,写入以下代码行:
((CChildFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();

在CMyProjView.cpp中,添加包含:

#include "ChildFrm.h"

转到CChildFrame包含文件,并将访问权限从protected更改为public。构建项目并运行它。选择窗口菜单中的“Split”。当点击一个窗格时,会绘制一个黄色边框。它显示哪个窗格有焦点。

自动分割是将视图分割成4个视图的能力,但不需要鼠标事件。这意味着CView被分割成4个视图,其中newWidth = oldWidth / 2,newHeight = oldHeight / 2。

首先,向CSplitterWnd类添加2个布尔值:

Public: bool m_bSplittingDone; protected: bool m_bIsAutomaticSplit;

在构造函数中初始化这些成员:

CSplitterWndEx::CSplitterWndEx() { m_bIsAutomaticSplit = false; m_bSplittingDone = false; }

要调用分割函数,需要使用CSplitterWnd::DoKeyboardSplit()。为类编写4个新方法:

public: BOOL DoAutomaticSplit(); // 新方法 BOOL DoKeyboardSplit(); // 重载 CSplitterWnd::DoKeyboardSplit(); protected: void StartTracking(int ht); // 重载 CSplitterWnd::StartTracking void StopTracking(BOOL bAccept); // 重载 CSplitterWnd::StopTracking

StartTracking方法保存当前光标,并在自动分割模式下立即恢复。StopTracking方法现在分割完成,m_bIsAutomaticSplit设置为false,m_bSplittingDone设置为true。DoAutomaticSplit方法保存当前鼠标位置,设置分割完成为false(当然),自动为true,然后分割。DoKeyboardSplit方法设置m_bSplittingDone为false,m_bIsAutomaticSplit为false,然后调用CSplitterWnd::DoKeyboardSplit()。

还需要重载OnMouseMove事件:

void CSplitterWndEx::OnMouseMove(UINT nFlags, CPoint pt) { if (m_bIsAutomaticSplit) { // 如果自动分割模式:不能选择分割条的位置 // -> 转到下一步 StopTracking(TRUE); return; } CSplitterWnd::OnMouseMove(nFlags,pt); }

注意,需要调用DoAutomaticSplit方法。可以在CChildFrame类中调用它:

void CChildFrame::AutomaticSplit() { // 设置计时器(只是一个技巧,在分割完成后执行操作) KillTimer(1); // 销毁旧计时器 SetTimer(1, 10, NULL); // 创建新计时器(索引=1;时间=10ms) m_wndSplitter.DoAutomaticSplit(); }

void CChildFrame::OnTimer(UINT nIDEvent) { if (m_wndSplitter.m_bSplittingDone) // 如果分割完成 { KillTimer(1); // 杀死计时器 // (只是一个技巧,在分割完成后执行操作) // 循环行和列 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) // 左上角 theView->DoSomething(RGB(255,0,0)); else if (r == 0 && c == 1) // 右上角 theView->DoSomething(RGB(0,255,0)); else if (r == 1 && c == 0) // 左下角 theView->DoSomething(RGB(0,0,255)); else if (r == 1 && c == 1) // 右下角 theView->DoSomething(RGB(255,255,0)); } } } }

void CChildFrame::OnWindowAutomaticsplit() { AutomaticSplit(); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485