此问题是先前发布的问题的后续问题,该问题部分尚未解决。
如何在 MFC SDI 应用程序中切换基于 OpenGL 的视图?
我有一个基于 MFC 的 Windows 桌面 SDI 应用程序,使用 Doc-View 框架构建,并将基于“现代”OpenGL 的图形显示为 MainFrame 中的默认视图。
我希望能够在应用程序运行时通过主菜单选项“切换视图”将应用程序默认视图类切换/切换为备用完全独立的视图类,以便备用视图类成为显示的活动视图.
我可以成功地在两个单独的视图类之间切换活动视图 - 但前提是辅助视图是非基于 OpenGL 的视图类(即使用默认的 Windows GDI 图形)。目前,出于测试目的,辅助视图仅呈现纯白色背景和静态硬编码文本消息,以确认它是所选的视图。
当我切换回 OpenGL 视图时,它完全处于切换之前的状态(即 OpenGL 视图没有“销毁”并保存在内存中)。
但是如果我尝试切换到同样基于 OpenGL 的第二个视图(但使用完全不同的着色器),则程序会崩溃并出现以下错误:
程序此时中断(崩溃):
任何人都可以建议这意味着什么或可能与什么相关吗?
用于在两个视图之间切换的事件处理程序代码如下所示。应用程序默认视图是“ModelView3D”,第二个 OpenGL 视图是“StaticView3D”。如上所述,当“StaticView3D”不使用 OpenGL(即标准 MFC 视图类)时,视图切换工作正常。
CView* CMFCAPPApp::SwitchView()
{
CView* pActiveView = ((CFrameWnd*)m_pMainWnd)->GetActiveView();
CView* pNewView = nullptr;
POSITION pos = AfxGetApp()->GetFirstDocTemplatePosition();
CDocTemplate* doc_template = AfxGetApp()->GetNextDocTemplate(pos);
if(!m_staticView3D)
m_staticView3D = (CView*) new StaticView3D;
if (NULL == m_staticView3D)
return FALSE;
// Initialize a CCreateContext to point to the active document.
// With this context, the new view is added to the document
// when the view is created in CView::OnCreate().
CCreateContext newContext;
newContext.m_pNewViewClass = NULL;
newContext.m_pNewDocTemplate = doc_template;
newContext.m_pLastView = NULL;
newContext.m_pCurrentFrame = NULL;
//set to NULL if the new View class will not use the Doc object
newContext.m_pCurrentDoc = NULL;
// The ID of the initial active view is AFX_IDW_PANE_FIRST.
// Incrementing this value by one for additional views works
// in the standard document/view case but the technique cannot
// be extended for the CSplitterWnd case.
UINT viewID = AFX_IDW_PANE_FIRST + 1;
CRect rect(0, 0, 0, 0); // Gets resized later.
if(!m_staticView3D->GetSafeHwnd())
m_staticView3D->Create(NULL, _T("StaticView3D"), WS_CHILD | WS_OVERLAPPEDWINDOW, rect, m_pMainWnd, viewID, &newContext); // WS_CHILD
// When a document template creates a view, the WM_INITIALUPDATE
// message is sent automatically. However, this code must
// explicitly send the message, as follows.
m_staticView3D->SendMessage(WM_INITIALUPDATE, 0, 0);
if (pActiveView == m_modelView3D)
pNewView = m_staticView3D;
else
pNewView = m_modelView3D;
// Exchange view window IDs so RecalcLayout() works.
#ifndef _WIN32
UINT temp = ::GetWindowWord(pActiveView->m_hWnd, GWW_ID);
::SetWindowWord(pActiveView->m_hWnd, GWW_ID, ::GetWindowWord(pNewView->m_hWnd, GWW_ID));
::SetWindowWord(pNewView->m_hWnd, GWW_ID, temp);
#else
UINT temp = ::GetWindowLong(pActiveView->m_hWnd, GWL_ID);
::SetWindowLong(pActiveView->m_hWnd, GWL_ID, ::GetWindowLong(pNewView->m_hWnd, GWL_ID));
::SetWindowLong(pNewView->m_hWnd, GWL_ID, temp);
#endif
pActiveView->ShowWindow(SW_HIDE);
pNewView->ShowWindow(SW_SHOW);
((CFrameWnd*)m_pMainWnd)->SetActiveView(pNewView);
((CFrameWnd*)m_pMainWnd)->RecalcLayout();
pNewView->Invalidate();
return pActiveView;
}