我遇到了一个非常奇怪的问题,窗口似乎正在擦除其内容,并且在擦除后没有重新绘制它。该对话框源自CDHtmlDialog
,我认为这是问题的一部分。发生某种非确定性代码执行,导致某些代码在某些情况下先于其他代码执行,而在其他情况下则相反。
涉及的消息处理程序有:
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()
The 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()
功能,因为它似乎与重绘系统没有任何关系。
因此,有时会发生的情况是,对话框内容会在调用之前以某种方式绘制CCalcDrillDownDlg::OnPaint()
。如果发生这种情况,则调用CDHtmlDialog::OnPaint()
将从窗口上擦除内容。
其他时候,在调用之前内容不会绘制在窗口上CCalcDrillDownDlg::OnPaint()
。如果发生这种情况,则调用CDHtmlDialog::OnPaint()
可能仍然会擦除尚未绘制的窗口上的内容,然后在调用后的某个时间CCalcDrillDownDlg::OnPaint()
,它会被重绘。
当系统正确重绘窗口时,Spy++ 不会捕获任何消息,因此我删除了此问题生成的消息。
有谁知道重绘是如何完成的以及为什么订单有时会被禁止?
Edit
以下是该内容的内容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>
Edit #2
进一步的调查似乎表明 CDHtmlDialog 类(或其基类)将绘制窗口,无论我是否CCalcDrillDownDlg::OnPaint()
calls CDHtmlDialog::OnPaint()
或者不是,这很奇怪而且不直观。 :(
另外,这似乎可能与线程相关,因为这似乎取决于渲染窗口所需的时间。如果需要很短的时间,则显示良好。如果需要半秒或更长时间,就会搞砸。
目前,我正在使用一种解决方法,其中我有m_bRepaint
类中的标志最初设置为true
。致电后CCalcDrillDownDlg::OnPaint()
它不是标志性的,我检查标志并强制调整大小。这不是最佳选择,因为它会导致初始闪烁,但至少可以确保绘制窗口的内容。
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;
}
Using Invalidate()
不起作用。我必须将其大小调整为当前大小以外的大小,然后再将其大小调整回来。
This CDHtmlDialog
class 是一个可以使用的 PITA,如果有选择的话我不建议任何人使用它。