OpenGL+MFC导致闪烁、不刷新等问题的解决方法

MFC+OpenGL去除闪烁的方法网上很多。例如: http://hi.baidu.com/piaoshi111/blog/item/66dba5ff643caa275c60083b.html

上文相当详细的解释了MFC中使用OpenGL的基本的流程。并给出了实现无闪烁的步骤。

现在给出第一个问题:如果你在MFC生成向导中选择了“拆分窗口”,你会发现即使重载了OnEraseBkgnd,也无法解决闪烁问题!

笔者经过排查,发现问题出现在CMainFrame中MFC帮你生成的如下代码:

//在MainFrm.h中:
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

//在MainFrm.cpp中:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
	CCreateContext* pContext)
{
	return m_wndSplitter.Create(this,
		2, 2,               // TODO: 调整行数和列数
		CSize(10, 10),      // TODO: 调整最小窗格大小
		pContext);
}
也就是说MFC为实现拆分窗口帮你重载了OnCreateClient函数。我们知道MainFrm继承自CFrameWnd。我们看一下CFrameWnd的OnCreateClient做了什么:
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext)
{
	// default create client will create a view if asked for it
	if (pContext != NULL && pContext->m_pNewViewClass != NULL)
	{
		if (CreateView(pContext, AFX_IDW_PANE_FIRST) == NULL)
			return FALSE;
	}
	return TRUE;
}

这里就创建了我们初始化OpenGL的视图类CxxxView了。

但是,如果使用了拆分,MFC会自动添加一个类型为CSplitterWnd的对象m_wndSplitter,而你的CxxxView类则仅仅是CSplitterWnd内部的视图罢了。

在改变窗口大小时,CSplitterWnd首先响应ON_WM_SIZE,然后在其响应函数中让CxxxView进一步处理。

CSplitterWnd的窗口大小要略大于其内部的CxxxView。因此CSplitterWnd自身的刷新会影响CxxxView的刷新而而导致闪烁。

那么解决方法,要么不使用拆分,这个绝对没有问题。

如果必须要拆分窗口,那么可能需要派生自己的CSplitterWnd类,修改其行为.

下一个问题,你可能遇到窗口不刷新,只有改变窗口大小的情况才刷新

这是因为你的CxxxView只重载了OnDraw的原因。OnDraw是如何被调用的?

参见*\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\viewcore.cpp

/
// CView drawing support
void CView::OnPaint()
{
	// standard paint routine
	CPaintDC dc(this);
	OnPrepareDC(&dc);
	OnDraw(&dc);
}

响应ON_WM_PAINT消息的是CView,他调用了你重载的OnDraw。正因为这里的CPaintDC dc(this);导致了窗口不能持续刷新。

要知道更详细的原因,请参见http://peipengshuai.blog.163.com/blog/static/1901226620123169431072/

你只需要知道,CPaintDC会从刷新消息队列中移除ON_WM_PAINT即可。移除后,如果窗口没有发生改变,就不会自动刷新。

因此,你需要做的很简单。自己响应你的CxxxView类的ON_WM_PAINT,并不要在里面使用CPaintDC dc(this);(注释掉)即可。

再下一个问题:最大化窗口后,窗口某些区域(如工具栏)无法刷新,留下空白

这个问题尚未得到完美解决方案。参考http://topic.csdn.net/t/20020220/16/534304.html,一说是驱动问题。暂时无法验证。

如果有解决方案,希望读者留言告之。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值