c++: RedrawWindow() 闪烁
Posted
技术标签:
【中文标题】c++: RedrawWindow() 闪烁【英文标题】:c++: RedrawWindow() Flickering 【发布时间】:2017-09-28 08:17:31 【问题描述】:作为一名使用从 CWnd 继承的自定义类构建自定义拆分器 Wnd 的开发人员。 最初,屏幕有一个窗口(自定义类 - CTile),它有两个按钮(垂直 - 拆分,水平 - 拆分)。 当用户单击两个按钮之一时,会出现红色拆分条并出现两个子窗口(CTile)。 如您所知,当用户拖动红色拆分条时,必须修改子窗口。 我这里说的是,就在这时,闪烁出现了。 父wnd只有三个元素(两个子窗口和一个分割栏),所以我认为它从不需要绘图内容。我的意思是 WM_PAINT 消息处理程序。 这是我的代码。
this->cDiv = new CDivider(this->wth_tile / 2, 1);
this->cDiv->CreateDivider(this, this->hgt_tile);
//cDiv is split bar I used custom class which is inherited from CWnd.
//CreateDivider() is also my self-defined method.
this->first_child = new CTile();
// As I mentioned above, CTile is divided child window which is also inherited from CWnd.
POINT pt;
pt.x = 0;
pt.y = 0;
this->first_child->CreateTile(this, this->cDiv->sd_pos, this->hgt_tile, pt);
this->second_child = new CTile();
pt.x = this->cDiv->sd_pos + 5;
pt.y = 0;
this->second_child->CreateTile(this, this->cDiv->sd_pos, this->hgt_tile, pt);
This is make movable split bar wnd creation code.
And next is about modified child window size while drag the split bar.
void CDivider::OnMouseMove(UINT nFlags, CPoint point)
// TODO: Add your message handler code here and/or call default
POINT pt;
HDC hdc;
RECT rect;
this->parentWnd->GetWindowRect(&rect);
//convert the mouse coordinates relative to the top-left of
//the window
ClientToScreen(&point);
pt = point;
pt.x -= rect.left;
pt.y -= rect.top;
if (this->sd_mode == 1)
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
if (GetCapture() == this && this->dragged)
this->sd_pos = pt.x;
if (pt.x != oldPos.x && nFlags & MK_LBUTTON)
this->length = this->parentWnd->hgt_tile;
this->MoveWindow(this->sd_pos, 0, 4, this->length);
this->parentWnd->ResizeParent();
this->parentWnd->Invalidate();
this->parentWnd->UpdateWindow();
TRACE("Resize Parent\n");
/*this->parentWnd->first_child->Invalidate();
this->parentWnd->second_child->Invalidate();*/
else if (this->sd_mode == 2)
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
if (GetCapture() == this && this->dragged)
this->sd_pos = pt.y;
if (pt.y != oldPos.y && nFlags & MK_LBUTTON)
this->Invalidate();
this->length = this->parentWnd->wth_tile;
this->MoveWindow(0, this->sd_pos, this->length, 4);
this->parentWnd->ResizeParent();
this->parentWnd->Invalidate();
this->parentWnd->UpdateWindow();
TRACE("Resize Parent\n");
/*this->parentWnd->first_child->Invalidate();
this->parentWnd->second_child->Invalidate();*/
CWnd::OnMouseMove(nFlags, point);
这里,parentWnd 是拆分栏的父窗口 - 只是父初始窗口。 first_child 和 second_child 是子窗口。 sd_mode 表示拆分方法 - 垂直和水平。
为什么这段代码不起作用?
【问题讨论】:
您创建的父窗口是否使用WS_CLIPCHILDREN
windows 样式?
WS_CLIPCHILDREN?我从未使用过 WS_CLIPCHILDREN。只有 WS_VISIBLE 和 WS_CHILD 用于创建窗口。 @VTT
【参考方案1】:
闪烁的发生是因为在大多数普通窗口中绘画是一个两阶段操作。 1. 删除背景,2. 重新绘制窗口。
所以问题是需要重绘的子窗口。关于不闪烁绘画的文章很多。
您还可以优化重绘,仅使受影响的窗口部分无效。您强制重绘整个窗口。那并不理想。在这种情况下,大部分窗口可能会闪烁。
顺便说一句:带有特定标志的 RedrawWindow 比调用 Invalidate/Update 序列更好,并且可能会更快。
另外,在拖动过程中,最好使用一种方法来绘制带有 XOR-Paining 的 Bars。并在 LButtonUp-Event 发生时更新窗口大小。 CSplitterWnd 这样做的方式......你有来源。调查一下。
【讨论】:
我会尝试遵循您关于子窗口重绘的想法。而关于window的具体部分,我觉得也不错。当您说“在拖动过程中使用 XOR-Painting 绘制 Bars 的方法可能会更好。”,您能否提供一些关于它的宝贵示例? 你有 MFC CSpiltterWnd 的源代码。只是看看它。您可以找到所需的一切。 好的,还有一件事要问。当您说“并在 LButtonUp-Event 发生时更新窗口大小”时,但应用程序需要在拖动拆分栏时显示窗口大小和其他信息。您对此有何看法? 在您想要的任何窗口中显示窗口大小,但稍后再调整大小...以上是关于c++: RedrawWindow() 闪烁的主要内容,如果未能解决你的问题,请参考以下文章