<think>我们之前讨论的是在MFC中通过消息传递机制实现视图切换。在消息处理函数中,我们创建了新的视图对象。现在,问题聚焦在:这个新创建的视图是否是一个新的视图类?
回答:
在之前的实现中,我们通过消息传递机制切换视图时,会动态创建新的视图对象。这个新视图对象可以是已有的视图类,也可以是新定义的视图类。关键在于我们在切换时指定的运行时类(CRuntimeClass*)。
解释:
1. 视图类的定义:在MFC中,视图类通常是从CView或其派生类(如CFormView、CListView等)派生的类。这些类支持动态创建(使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏)。
2. 视图切换过程:
- 当需要切换视图时,我们调用SwitchView函数,并传入目标视图类的CRuntimeClass指针(例如RUNTIME_CLASS(CNewRightView))。
- 在消息处理函数OnViewSwitch中,我们使用传入的CRuntimeClass来动态创建该类的对象(使用CreateObject方法)。
- 然后,我们创建视图窗口,并将其显示在分割窗口的右 pane 中。
3. 新视图类:
- 如果传入的CRuntimeClass指向一个之前未使用过的视图类(例如新创建的CNewRightView类),那么这就是一个新创建的视图类实例。
- 如果传入的是已经存在的视图类(如初始的CInitialRightView),那么我们会创建该类的另一个实例(除非我们使用视图缓存,复用已有实例)。
4. 视图类的生命周期:
- 在切换视图时,我们会销毁当前的右视图(如果存在),然后创建新的视图对象。因此,每次切换都会创建一个新的视图对象(除非使用缓存)。
- 新创建的视图对象与文档关联(通过CCreateContext设置文档指针),因此可以访问文档数据。
示例代码片段(来自之前的实现):
```cpp
// 在OnViewSwitch函数中:
// 创建新视图
CView* pNewView = (CView*)pParam->pViewClass->CreateObject();
if (!pNewView) return 0;
// 创建视图窗口
if (!pNewView->Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
rect, &m_wndSplitter, 0, &context)) {
delete pNewView;
return 0;
}
```
5. 视图类的设计:
- 每个视图类负责特定的显示和交互功能。
- 例如,初始右视图类(CInitialRightView)可能包含一个按钮,点击后切换到新视图(CNewRightView)。
- 新视图类(CNewRightView)则可能包含不同的控件和功能。
因此,在切换视图时,我们创建的是指定视图类的一个新实例(对象),而不是定义一个新的视图类。视图类本身是在代码中预先定义好的。
但是,如果我们需要一个新的视图类型(例如显示图表的视图),那么我们就需要先创建一个新的视图类(如CChartView),然后就可以在切换时使用这个新类。
创建新视图类的步骤:
1. 使用类向导添加新的MFC类,继承自CView(或其它视图基类)。
2. 在类声明中使用DECLARE_DYNCREATE宏。
3. 在类实现中使用IMPLEMENT_DYNCREATE宏。
4. 重写必要的虚函数(如OnInitialUpdate, OnDraw等)。
5. 设计视图的界面(如果是CFormView,则设计对话框资源)。
这样,我们就可以在切换视图时使用这个新视图类。
总结:
在消息传递机制中切换的视图可以是:
- 已经存在的视图类(如初始视图类)的新实例
- 也可以是新定义的视图类(如CChartView)的实例
所以,问题中的“新创建的视图类”实际上是指新创建的视图对象,它属于一个已有的视图类(可能是新编写的类,也可能是旧的)。视图类的定义是在编码阶段完成的,而视图对象是在运行时动态创建的。
相关问题:
根据问题,用户可能关心如何定义新的视图类,以及如何在切换时使用它们。
§§相关问题§§:
1. 如何在MFC中创建一个新的视图类?
2. 如何使一个视图类支持动态创建?
3. 在视图切换时,如何传递参数给新视图?
4. 如何管理多个视图共享的文档数据?</think># 视图类的创建与使用详解
在MFC应用中,"新创建的视图类"指的是在运行时动态创建的视图对象,而不是在编译时静态定义的类。让我们深入探讨这个概念及其实现方式。
## 视图类的创建机制
### 1. 视图类的定义
视图类是在编译时定义的类,继承自`CView`或其派生类:
```cpp
// 初始右视图类 (编译时定义)
class CInitialRightView : public CFormView {
DECLARE_DYNCREATE(CInitialRightView)
public:
CInitialRightView();
virtual ~CInitialRightView();
// 按钮处理函数
afx_msg void OnBtnShowNewView();
DECLARE_MESSAGE_MAP()
};
// 新视图类 (编译时定义)
class CNewRightView : public CFormView {
DECLARE_DYNCREATE(CNewRightView)
public:
CNewRightView();
virtual ~CNewRightView();
// 返回按钮处理
afx_msg void OnBtnReturn();
DECLARE_MESSAGE_MAP()
};
```
### 2. 视图对象的创建
在运行时动态创建视图对象:
```cpp
// 在框架类中创建视图对象
LRESULT CMainFrame::OnViewSwitch(WPARAM wParam, LPARAM lParam) {
ViewSwitchParam* pParam = reinterpret_cast<ViewSwitchParam*>(lParam);
// 使用运行时类信息创建视图对象
CView* pNewView = (CView*)pParam->pViewClass->CreateObject();
// 创建视图窗口
pNewView->Create(
NULL, // 类名
NULL, // 窗口名
WS_CHILD | WS_VISIBLE, // 样式
rect, // 位置和大小
&m_wndSplitter, // 父窗口
0, // 子窗口ID
&context // 创建上下文
);
// 初始化视图
pNewView->OnInitialUpdate();
}
```
## 视图对象的动态创建过程
### 1. 运行时类系统 (CRuntimeClass)
MFC使用运行时类系统实现动态创建:
```cpp
// 视图类声明
class CNewRightView : public CFormView {
DECLARE_DYNCREATE(CNewRightView) // 声明动态创建支持
// ...
};
// 视图类实现
IMPLEMENT_DYNCREATE(CNewRightView, CFormView) // 实现动态创建
// 动态创建机制实现
CObject* CRuntimeClass::CreateObject() {
if (m_pfnCreateObject == NULL) {
TRACE1("Error: Trying to create object which is not DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n", m_lpszClassName);
return NULL;
}
return (*m_pfnCreateObject)(); // 调用创建函数
}
```
### 2. 视图创建流程
1. **获取运行时类信息**:
```cpp
CRuntimeClass* pClass = RUNTIME_CLASS(CNewRightView);
```
2. **创建对象实例**:
```cpp
CObject* pObj = pClass->CreateObject();
```
3. **创建窗口**:
```cpp
pView->Create(...); // 创建实际窗口
```
4. **初始化视图**:
```cpp
pView->OnInitialUpdate(); // 初始化视图
```
## 视图生命周期管理
### 1. 视图创建
```cpp
// 创建视图的完整过程
CView* CreateViewInstance(CRuntimeClass* pViewClass, CWnd* pParent, CCreateContext* pContext) {
// 创建视图对象
CView* pView = (CView*)pViewClass->CreateObject();
if (!pView) return nullptr;
// 创建视图窗口
if (!pView->Create(NULL, NULL, WS_CHILD | WS_VISIBLE,
CRect(0, 0, 0, 0), pParent, AFX_IDW_PANE_FIRST, pContext)) {
delete pView;
return nullptr;
}
// 初始化视图
pView->OnInitialUpdate();
return pView;
}
```
### 2. 视图销毁
```cpp
// 安全销毁视图
void DestroyViewInstance(CView* pView) {
if (pView) {
// 保存状态(可选)
SaveViewState(pView);
// 销毁窗口
pView->DestroyWindow();
// 删除对象
delete pView;
}
}
```
## 视图状态管理
### 1. 视图状态保存/恢复
```cpp
// 视图状态管理类
class CViewStateManager {
public:
void SaveState(CView* pView, const CString& state) {
CString className = typeid(*pView).name();
m_stateMap[className] = state;
}
CString RestoreState(CView* pView) {
CString className = typeid(*pView).name();
auto it = m_stateMap.find(className);
return (it != m_stateMap.end()) ? it->second : CString();
}
private:
std::map<CString, CString> m_stateMap;
};
// 在视图切换时使用
void SwitchView(CRuntimeClass* pNewClass) {
// 保存当前视图状态
CString currentState = GetCurrentViewState();
m_stateManager.SaveState(m_pCurrentView, currentState);
// 创建新视图
CView* pNewView = CreateViewInstance(pNewClass, ...);
// 恢复新视图状态
CString savedState = m_stateManager.RestoreState(pNewView);
if (!savedState.IsEmpty()) {
RestoreViewState(pNewView, savedState);
}
}
```
### 2. 具体视图状态处理
```cpp
// 在具体视图类中实现状态保存/恢复
class CDataGridView : public CView {
public:
CString GetState() const {
CString state;
// 保存列宽、排序等状态
state.Format(_T("%d,%d,%d"), m_sortColumn, m_sortAscending, m_pageSize);
return state;
}
void RestoreState(LPCTSTR lpszState) {
if (lpszState && *lpszState) {
int sortCol, sortAsc, pageSize;
if (_stscanf_s(lpszState, _T("%d,%d,%d"), &sortCol, &sortAsc, &pageSize) == 3) {
m_sortColumn = sortCol;
m_sortAscending = (sortAsc != 0);
m_pageSize = pageSize;
}
}
}
};
```
## 高级视图管理技术
### 1. 视图缓存
```cpp
class CViewManager {
public:
CView* GetView(CRuntimeClass* pViewClass) {
// 查找缓存
auto it = m_viewCache.find(pViewClass);
if (it != m_viewCache.end()) {
return it->second;
}
// 创建新视图
CView* pView = CreateViewInstance(pViewClass, ...);
if (pView) {
m_viewCache[pViewClass] = pView;
pView->ShowWindow(SW_HIDE); // 初始隐藏
}
return pView;
}
void ShowView(CRuntimeClass* pViewClass) {
CView* pView = GetView(pViewClass);
if (pView) {
// 隐藏所有视图
for (auto& pair : m_viewCache) {
pair.second->ShowWindow(SW_HIDE);
}
// 显示目标视图
pView->ShowWindow(SW_SHOW);
pView->SetFocus();
}
}
private:
std::map<CRuntimeClass*, CView*> m_viewCache;
};
```
### 2. 视图工厂模式
```cpp
// 视图工厂接口
class IViewFactory {
public:
virtual CView* CreateView(CWnd* pParent, CCreateContext* pContext) = 0;
};
// 具体视图工厂
template <class T>
class TViewFactory : public IViewFactory {
public:
CView* CreateView(CWnd* pParent, CCreateContext* pContext) override {
CView* pView = new T;
CRect rect;
pParent->GetClientRect(rect);
if (pView->Create(NULL, NULL, WS_CHILD, rect, pParent, AFX_IDW_PANE_FIRST, pContext)) {
pView->OnInitialUpdate();
return pView;
}
delete pView;
return nullptr;
}
};
// 视图工厂注册
class CViewFactoryRegistry {
public:
template <class T>
void RegisterView(LPCTSTR lpszName) {
m_factories[lpszName] = std::make_unique<TViewFactory<T>>();
}
CView* CreateView(LPCTSTR lpszName, CWnd* pParent, CCreateContext* pContext) {
auto it = m_factories.find(lpszName);
if (it != m_factories.end()) {
return it->second->CreateView(pParent, pContext);
}
return nullptr;
}
private:
std::map<CString, std::unique_ptr<IViewFactory>> m_factories;
};
```
## 视图与文档的交互
### 1. 文档更新通知
```cpp
// 文档类
class CMyDocument : public CDocument {
public:
void UpdateData() {
// 更新数据...
UpdateAllViews(NULL); // 通知所有关联视图
}
};
// 视图类
void CMyView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) {
switch (lHint) {
case UPDATE_DATA:
// 处理数据更新
RefreshDisplay();
break;
case UPDATE_LAYOUT:
// 处理布局更新
AdjustLayout();
break;
}
}
```
### 2. 视图特定更新
```cpp
// 只更新特定视图
void CMyDocument::UpdateSpecificView(CView* pTargetView) {
POSITION pos = GetFirstViewPosition();
while (CView* pView = GetNextView(pos)) {
if (pView == pTargetView) {
pView->OnUpdate(NULL, UPDATE_SPECIFIC, NULL);
break;
}
}
}
```
## 总结:视图类的创建与使用
1. **视图类 vs 视图对象**:
- **视图类**:在编译时定义的类(如 `CInitialRightView`)
- **视图对象**:在运行时动态创建的实例
2. **创建过程**:
- 使用 `DECLARE_DYNCREATE` 和 `IMPLEMENT_DYNCREATE` 宏支持动态创建
- 通过 `CRuntimeClass::CreateObject()` 创建对象实例
- 调用 `Create()` 方法创建实际窗口
- 调用 `OnInitialUpdate()` 初始化视图
3. **生命周期管理**:
- 创建:动态分配内存并创建窗口
- 销毁:调用 `DestroyWindow()` 并删除对象
- 缓存:可选地缓存视图对象以提高性能
4. **状态管理**:
- 在切换视图时保存/恢复视图状态
- 使用序列化或自定义格式保存状态
5. **高级技术**:
- 视图缓存减少创建开销
- 工厂模式统一创建接口
- 文档-视图通信机制
在MFC应用中,视图切换时创建的是**视图对象的新实例**,这些实例属于预先定义的视图类。每次切换可能会创建新的对象实例(除非使用缓存),但这些实例都属于同一个编译时定义的类。