c ++:RedrawWindow()闪烁

时间:2017-09-28 08:17:32

标签: c++ mfc

作为使用从CWnd继承的自定义类构建Custome Splitter 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意味着分割方法 - 垂直&水平的。

为什么这段代码不起作用?

1 个答案:

答案 0 :(得分:2)

闪烁的发生是因为绘画在大多数正常窗口中都是两相操作。 1.背景被删除,2。窗口重新粉刷。

所以问题是需要重绘的子窗口。有很多关于非闪烁画的文章。

此外,您可以优化重绘,只是使受影响的窗口部分无效。您强制重绘完整的窗口。这不是理想的。在这种情况下,窗口的大部分可能会闪烁。

BTW:具有特定标志的RedrawWindow比调用Invalidate / Update序列更好,并且可以更快地打勾。

在拖动过程中使用方法绘制带有XOR-Paining的条形图可能更好。并在LButtonUp-Event发生时更新窗口大小。 CSplitterWnd正在做的方式......你有源。看看吧。