2016-06-17 3 views
6

У меня возникает эта очень странная проблема, когда окно, кажется, стирает его содержимое, а не перерисовывает его после его стирания. Этот диалог получен от 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() 

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 ++ не записывает никаких сообщений, когда система правильно перерисовывает окно, поэтому я удалил сообщения, созданные из этого вопроса.

Есть ли у кого-нибудь идеи относительно того, как выполняется перерисовка, и почему заказ иногда становится foobarred?

Редактировать

Вот содержимое 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()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; 
    } 

Использование Invalidate() не работает.Я должен изменить его размер на другой, чем текущий размер, и изменить его размер.

Этот класс CDHtmlDialog является PITA для работы, и я бы не рекомендовал никому его использовать, если у них есть выбор.

+0

Без [mcve] мы можем только догадываться. – theB

+0

@theB, если бы я мог это сделать, я бы сделал это. Некоторые возможные предложения были бы приятными. – Adrian

+0

Если вы не можете предоставить [mcve], предоставьте соответствующий фрагмент кода. –

ответ

0

Ok, так что, казалось бы, что это вызвано очереди окна сообщений не является детерминированным, так что, казалось бы, что лежащий в основе COM управления окрашивая его в DC до сообщения WM_PAINT.

Чтобы обойти эту проблему, я жду окна, чтобы показать себя, ожидая WM_WINDOWPOSCHANGED сообщения, отправляя еще одно сообщение приложение, которое будет вызывать Invalidate() и UpdateWindow(), тем самым принуждая перерисовки окна.

Этот метод описан here в блоге Раймонда Чена «Старая новая вещь».

-1

Поскольку OnEraseBkgnd() вызывается перед OnPaint()

ON_WM_ERASEBKGND() 
... 

BOOL CCalcDrillDownDlg::OnEraseBkgnd(CDC* pDC) 
{ 
    // TODO: Add your message handler code here and/or call default 
    return TRUE; 
} 
+0

Итак, я не уверен, что вы говорите, я должен здесь. Если 'OnEraseBkgnd() вызывается перед OnPaint()', то почему не будет ли рисовать окно после его стирания? И почему это стирается? – Adrian

+0

В CDHtmlDialog OnPaint() неэффективен для выполнения перерисовки. Обычно html-страница будет накладывать на любой рисунок, поэтому его нельзя перерисовать. Недостаточно информации, чтобы доказать это дальше. –

+0

Итак, если это так, вы хотите использовать 'OnEraseBkgnd()' для использования вместо 'OnPaint()'? – Adrian

Смежные вопросы