为什么对话框不刷新就删除其内容? [英] Why would a dialog erase its content without refreshing?

查看:72
本文介绍了为什么对话框不刷新就删除其内容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个非常奇怪的问题,其中一个窗口似乎正在擦除其内容,并且在擦除后不重新绘制它.此对话框是从CDHtmlDialog派生的,我认为这是问题的一部分.发生某种不确定的代码执行,导致某些代码在某些情况下先于其他代码执行,而在另一些情况下则相反.

I'm having this very strange problem where a window seems to be erasing its content and not redrawing it after erasing it. This dialog is derived from CDHtmlDialog, which I think is part of the problem. There is some sort of non-deterministic code execution happening resulting in some code being executed prior to others in certain cases and the opposite in others.

涉及的消息处理程序为:

Message handlers that are involved are:

BEGIN_MESSAGE_MAP(CCalcDrillDownDlg, CDHtmlDialog)
    ON_WM_PAINT()
END_MESSAGE_MAP()

BEGIN_EVENTSINK_MAP(CCalcDrillDownDlg, CDHtmlDialog)
     ON_EVENT(CCalcDrillDownDlg, AFX_IDC_BROWSER, 250 /* BeforeNavigate2 */, _OnBeforeNavigate2b, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)
END_EVENTSINK_MAP()

OnInitDialog()函数如下:

BOOL CCalcDrillDownDlg::OnInitDialog()
{
    SetHostFlags(DOCHOSTUIFLAG_FLAT_SCROLLBAR);

    CDHtmlDialog::OnInitDialog(); // << will eventually call _OnBeforeNavigate2b()

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    LoadFromResource(IDR_CALC_DRILLDOWN); // << will eventually call _OnBeforeNavigate2b()
    CString title = getStr2Ptr(22574);
    SetWindowText(title);
    ShowWindow(SW_SHOW);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

这是OnPaint()函数:

void CCalcDrillDownDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDHtmlDialog::OnPaint();
    }
}

我没有放置_OnBeforeNavigate2b()函数的内容,因为它似乎与重绘系统没有任何关系.

I've not put the contents of the _OnBeforeNavigate2b() function as it appears not to have anything to do with the redrawing system.

所以似乎发生的情况是,有时,在调用CCalcDrillDownDlg::OnPaint()之前,将以某种方式绘制对话框的内容.如果发生这种情况,则对CDHtmlDialog::OnPaint()的调用将清除窗口中的内容.

So what appears to happen is that sometimes, the dialog contents will be painted somehow prior to calling CCalcDrillDownDlg::OnPaint(). If this happens, then the call to CDHtmlDialog::OnPaint() will wipe the contents off the window.

有时,在调用CCalcDrillDownDlg::OnPaint()之前,内容不会绘制在窗口上.如果发生这种情况,则对CDHtmlDialog::OnPaint()的调用可能仍会清除窗口上尚未绘制的内容,然后在对CCalcDrillDownDlg::OnPaint()的调用后的某个时间重新绘制它.

Other times, the contents are not painted on the window prior to calling CCalcDrillDownDlg::OnPaint(). If this happens, then the call to CDHtmlDialog::OnPaint() will probably still wipe the contents off the window, which hasn't been painted yet, and then sometime after the call to CCalcDrillDownDlg::OnPaint(), it gets redrawn.

当系统正确地重绘窗口时,Spy ++不会捕获任何消息,因此我已删除了从此问题生成的消息.

Spy++ doesn't capture any messages when the system properly redraws the window, so I've removed the messages generated from this question.

有人对重新绘制如何完成以及为什么有时使订单变得愚蠢有任何想法吗?

Does anyone have any idea as to how the redrawing is getting done and why the order gets foobarred sometimes?

这是IDR_CALC_DRILLDOWN资源的内容:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Calculation Drilldown</title>
    <style type="text/css">
        body { overflow-y: auto; font-family: arial, Helvetica, sans-serif; font-size: 90%; }

        a:link { color: black; }
        a:visited { color: black; }
        table { border-collapse: collapse; }

        tr.runcache td { background-color: #B5B5B5; color: black; }
        tr.runcache td a:link { color: black; }
        tr.runcache td a:visited { color: black; }

        tr.tracker td { background-color: white; color: black; }
        tr.tracker td a:link { color: black; }
        tr.tracker td a:visited { color: black; }

        td.numericvalue { text-align: right; }

        tr.paramTitle td { background-color: #4A4A4A; color: white; }

        tr.resultTitle td { background-color: #4A4A4A; color: white; }
        tr.resultTitle td a:link { color: white; }
        tr.resultTitle td a:visited { color: white; }

        tr.param td { background-color: white; color: black; }
        tr.param td a:link { color: black; }
        tr.param td a:visited { color: black; }

        span.selection { background-color: #EBEBEB; }
    </style>
</head>
<body>
    <div id="calculation"></div>
    <div id="details" style="padding-left: 0.1in; display: none;"></div>
</body>
</html>

编辑#2

进一步的研究似乎表明CDHtmlDialog类(或其基类)将绘制窗口,而与我的CCalcDrillDownDlg::OnPaint()是否调用CDHtmlDialog::OnPaint()无关,这只是很奇怪且不直观. :(

Edit #2

Further investigation seems to show that the CDHtmlDialog class (or a base class thereof) will draw the window, irrespective of if my CCalcDrillDownDlg::OnPaint() calls CDHtmlDialog::OnPaint() or not, which is just weird and not intuitive. :(

此外,这似乎可能与线程相关,因为这似乎取决于渲染窗口所花费的时间.如果需要很短的时间,它将显示正常.如果要花费半秒或更长时间,则会拧紧.

Also, it seems that this is possibly threading related, as this seems to be dependant on how long it takes to render the window. If it takes a short time, it displays fine. If it takes a half a second or more, it screws up.

目前,我正在使用一种变通方法,其中在类中最初设置为true的类中有一个m_bRepaint标志.调用CCalcDrillDownDlg::OnPaint()之后,它不是图标,我检查该标志并强制调整大小.这不是最佳选择,因为它会引起初始闪烁,但至少可以确保绘制了窗口的内容.

For the moment, I'm using a workaround where I have a m_bRepaint flag in the class which is initially set to true. Upon calling CCalcDrillDownDlg::OnPaint() and it is not iconic, I check the flag and force a resize. This is not optimal as it causes an initial flicker, but it at least it makes sure that the window's contents are drawn.

    if (!m_bRepaint)
    {
        CDHtmlDialog::OnPaint();
    }
    else
    {
        CRect winRect;
        GetWindowRect(&winRect);
        SetWindowPos(NULL, 0, 0, winRect.Width() - 1, winRect.Height(), SWP_NOMOVE | SWP_NOZORDER);
        SetWindowPos(NULL, 0, 0, winRect.Width()    , winRect.Height(), SWP_NOMOVE | SWP_NOZORDER);
        m_bRepaint = false;
    }

使用Invalidate()不起作用.我必须将其调整为当前大小以外的其他大小,然后重新调整大小.

Using Invalidate() does not work. I have to resize it to something other than it's current size and resize it back.

CDHtmlDialog类是可以使用的PITA,如果有选择,我不建议任何人使用它.

This CDHtmlDialog class is a PITA to work with and I wouldn't recommend anybody use it if they have a choice.

推荐答案

好吧,所以这似乎是由于Windows消息队列的不确定性引起的,因此似乎在下面的COM控件正在绘制是WM_PAINT消息之前的DC.

Ok, so it would seem that this is caused by the windows message queue not being deterministic, so it would seem that the underlying COM control is painting on it's DC prior to the WM_PAINT message.

要解决此问题,我等待窗口显示,方法是等待WM_WINDOWPOSCHANGED消息,然后发布另一条应用程序消息,该消息随后将调用Invalidate()UpdateWindow(),从而强制重新绘制窗口.

To workaround the issue, I wait for the window to show itself by waiting for WM_WINDOWPOSCHANGED message, posting another application message which will then call Invalidate() and UpdateWindow(), thus forcing the redrawing of the window.

此处描述了此技术博客旧事物".

This technique is described here on Raymond Chen's blog "The Old New Thing".

这篇关于为什么对话框不刷新就删除其内容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆