如何调用 OnEraseBkgnd() 在另一个函数中重新绘制窗口? (MFC)
Posted
技术标签:
【中文标题】如何调用 OnEraseBkgnd() 在另一个函数中重新绘制窗口? (MFC)【英文标题】:How to call OnEraseBkgnd() to repaint the window in another function? (MFC) 【发布时间】:2016-12-03 02:06:52 【问题描述】:我正在尝试调用OnEraseBkgnd()
在另一个函数中重新绘制窗口。
比如下面的代码:
...
CBitmap Background;
BITMAP bm;
CDC dcMemory;
int width, height;
...
BOOL CSplashDlg::OnInitDialog()
CDialog::OnInitDialog();
CDC* dc;
Background.LoadBitmap(IDB_COVER); //Load Bitmap
Background.GetBitmap(&bm); //Load Bitmap into handle
width = 0;
height = 0;
while(width < 300)
width += 10;
height += 10;
OnEraseBkgnd(dc); //<--- Here I want to call OnEraseBkgnd()
Sleep(5); //Delay 5 millisecond
return TRUE;
BOOL CSplashDlg::OnEraseBkgnd(CDC* pDC)
///////////////////////////////////
Invalidate(); //I don't know where I should put this function
///////////////////////////////////
dcMemory.CreateCompatibleDC(pDC);
CBitmap *pOldbmp = dcMemory.SelectObject(&Background);
pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(0, 0, width, height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
return TRUE;
在上面的例子中,我想在OnInitDialog()
内部执行时调用OnEraseBkgnd()
来重新绘制窗口。我搜索了互联网,它总是说使用Invalidate();
或RedrawWindow();
重新绘制它,它还会调用OnEraseBkgnd()
函数。问题是:我应该如何使用Invalidate();
或RedrawWindow();
?我应该把这些功能放在哪里?
我已经把这两个函数放在了任何地方,但它仍然不起作用。
编辑:
我已经修改过了。虽然现在Invalidate()
和UpdateWindow()
成功调用了OnEraseBkgnd()
函数。但是我发现了另一个问题:为什么我使用Invalidate()
或UpdateWindow()
重新绘制它时StretchBlt
不起作用,但FillSolidRect
起作用?
...
BOOL CMainDlg::OnInitDialog()
CSplashDlg Frame;
Frame.width = 0;
Frame.height = 0;
while(Frame.width <= 300)
Frame.width += 10;
Frame.height += 10;
Frame.Invalidate(); //<---Here I use both Invalidate() and UpdateWindow()
Frame.UpdateWindow(); //<---Here I use both Invalidate() and UpdateWindow()
Sleep(5); //Delay 5 millisecond
CDialog::OnInitDialog();
return TRUE;
BOOL CSplashDlg::OnInitDialog()
CDialog::OnInitDialog();
width = 0;
height = 0;
Background.LoadBitmap(IDB_COVER); //Load Bitmap
Background.GetBitmap(&bm); //Load Bitmap into handle
return TRUE;
BOOL CSplashDlg::OnEraseBkgnd(CDC* pDC)
dcMemory.CreateCompatibleDC(pDC);
CBitmap *pOldbmp = dcMemory.SelectObject(&Background);
///////////////////////////////////////////////////////////////
pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(0, 0, width, height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); //It doesn't work when using this one (StretchBlt)
///////////////////////////////////////////////////////////////
pDC->FillSolidRect(0, 0, width, height, RGB(255,0,0)); //But it works when using this one (FillSolidRect)
///////////////////////////////////////////////////////////////
return TRUE;
...
【问题讨论】:
***.com/questions/2183649/… 在OnInitDialog
返回之前,对话框不可见。你可以在OnInitDialog
中做的是创建一个5 毫秒的定时器SetTimer(1, 5, 0)
,将ON_WM_TIMER
添加到消息映射中,然后在OnTimer(UINT_PTR)
中调用Invalidate()
。画在OnPaint
,而不是OnEraseBkgnd
在您的第二次编辑中,一切都正确,除了Frame->Invalidate
Windows 消息被阻止后,它不会更新窗口,因为系统仍在处理另一条消息 (WM_INITDIALOG
)。您在它之后调用UpdateWindow
,希望说服Windows 处理该消息,但它仍然没有这样做。唯一的选择是在两者之间插入一个消息循环(使用PeekMessage
),以处理消息队列中的当前消息,但您必须小心。或使用WM_TIMER
执行此操作
【参考方案1】:
您永远不应该调用OnEraseBkgnd( )
和OnPaint( )
之类的名称。当需要绘图时,MFC 会调用这些。你的工作是处理OnEraseBkgnd( )
的绘制需求。
Invalidate( )
导致 MFC 更新绘图区域,然后它将调用 OnEraseBkgnd( )
和 OnPaint( )
。如果您在OnPaint( )
或OnEraseBkgnd( )
中使用Invalidate( )
,则程序可能会挂起,因为它会导致重绘窗口的无限循环。
您可以在OnInitDialog( )
中致电Invalidate( )
,但可能没有必要。
所以从OnEraseBkgnd( )
中取出Invalidate,不要在OnInitDialog( )
中调用OnEraseBkgnd( )
并从那里开始。
你也必须有
ON_WM_PAINT( )
ON_WM_ERASEBKGND( )
在 MFC 调用的消息映射中。
注意: 我不相信重新发明***。大部分都是以前做过的。我没有在我的项目中使用闪屏,但如果需要,我会从这里开始:Splash Screen C++ Class using MFC。
我没有下载和查看代码,但有四颗星,它应该是一个不错的起点。 MFC 不是一夜之间就能学会的。当我开始时,我阅读书籍和大量搜索来学习。您只是无法猜测基础架构的工作原理。希望这会有所帮助...
【讨论】:
我已将Invalidate()
放入OnInitDialog()
并将ON_WM_ERASEBKGND()
添加到消息映射中,但它仍然没有重绘任何内容。
@BananaCode 调用Invalidate
只是标记要重新绘制的窗口。要查看更改,您需要在失效后调用UpdateWindow
,不要失效并调用RedrawWindow
,或者在失效后运行消息循环。
我发现了另一个问题:为什么当我使用Invalidate()
或UpdateWindow()
时StretchBlt
不起作用但FillSolidRect
起作用?代码在更新的内容中。
那么这告诉您问题可能与位图有关。您确定 IDB_COVER 是有效资源吗?我看不到其他任何东西,您的代码应该可以工作。我“相当”确定我没有错过什么。以上是关于如何调用 OnEraseBkgnd() 在另一个函数中重新绘制窗口? (MFC)的主要内容,如果未能解决你的问题,请参考以下文章