Prevent constant size changes in native MSW wxProgressDialog

MSW implementation of wxProgressDialog adjusted the dialog size to the
size of the message shown in it on each update, resulting in visually
unpleasant constant jumping around (this is the same problem that we
used to have in wxGenericProgressDialog long time ago, see #10624).

Minimize this by using TDM_UPDATE_ELEMENT_TEXT instead of
TDM_SET_ELEMENT_TEXT for changing the element text. This still increases
the dialog size if the new element text is longer than the old value,
but at least doesn't shrink it back if it is shorter, which is already
quite an improvement.

Notice that this change requires using TDF_EXPAND_FOOTER_AREA style, as
otherwise the expanded information can't be updated without a re-layout.
But this doesn't seem to be a big loss and it's not really clear why did
we explicitly clear this flag before anyhow.

Update the dialogs sample to make it easy to test for this behaviour and
the documentation to mention MSW version peculiarities.
This commit is contained in:
Vadim Zeitlin 2017-10-27 00:01:18 +02:00
parent 6d2f903a48
commit 0736bdfb28
3 changed files with 52 additions and 10 deletions

View File

@ -194,7 +194,9 @@ public:
Notice that you may want to call Fit() to change the dialog size to
conform to the length of the new message if desired. The dialog does
not do this automatically.
not do this automatically, except for the native MSW implementation
which does increase the dialog size if necessary (but still doesn't
shrink it back even if the text becomes shorter).
@param value
The new value of the progress meter. It should be less than or equal to

View File

@ -349,7 +349,20 @@ bool MyApp::OnInit()
);
for ( int i = 0; i <= PROGRESS_COUNT; i++ )
{
if ( !dlg.Update(i) )
wxString msg;
switch ( i )
{
case 15:
msg = "And the same dialog but with a very, very, very long"
" message, just to test how it appears in this case.";
break;
case 30:
msg = "Back to brevity";
break;
}
if ( !dlg.Update(i, msg) )
break;
wxMilliSleep(50);

View File

@ -81,6 +81,7 @@ public:
m_value = 0;
m_progressBarMarquee = false;
m_skipped = false;
m_msgChangeElementText = TDM_SET_ELEMENT_TEXT;
m_notifications = 0;
m_parent = NULL;
}
@ -105,6 +106,14 @@ public:
bool m_progressBarMarquee;
bool m_skipped;
// The task dialog message to use for changing the text of its elements:
// it's TDM_SET_ELEMENT_TEXT initially as this message should be used to
// let the dialog adjust itself to the size of its elements, but
// TDM_UPDATE_ELEMENT_TEXT later to prevent the dialog from performing a
// layout on each update, which is annoying as it can result in its size
// constantly changing.
int m_msgChangeElementText;
// Bit field that indicates fields that have been modified by the
// main thread so the task dialog runner knows what to update.
int m_notifications;
@ -260,14 +269,27 @@ void PerformNotificationUpdates(HWND hwnd,
}
::SendMessage( hwnd,
TDM_SET_ELEMENT_TEXT,
sharedData->m_msgChangeElementText,
TDE_MAIN_INSTRUCTION,
wxMSW_CONV_LPARAM(title) );
::SendMessage( hwnd,
TDM_SET_ELEMENT_TEXT,
sharedData->m_msgChangeElementText,
TDE_CONTENT,
wxMSW_CONV_LPARAM(body) );
// After using TDM_SET_ELEMENT_TEXT once, we don't want to use it for
// the subsequent updates as it could result in dialog size changing
// unexpectedly, so reset it (which does nothing if we had already done
// it, of course, but it's not a problem).
//
// Notice that, contrary to its documentation, even using this message
// still increases the dialog size if the new text is longer (at least
// under Windows 7), but it doesn't shrink back if the text becomes
// shorter later and stays at the bigger size which is still a big gain
// as it prevents jumping back and forth between the smaller and larger
// sizes.
sharedData->m_msgChangeElementText = TDM_UPDATE_ELEMENT_TEXT;
}
if ( sharedData->m_notifications & wxSPDD_EXPINFO_CHANGED )
@ -276,8 +298,15 @@ void PerformNotificationUpdates(HWND hwnd,
sharedData->m_expandedInformation;
if ( !expandedInformation.empty() )
{
// Here we never need to use TDM_SET_ELEMENT_TEXT as the size of
// the expanded information doesn't change drastically.
//
// Notice that TDM_UPDATE_ELEMENT_TEXT for this element only works
// when using TDF_EXPAND_FOOTER_AREA, as we do. Without this flag,
// only TDM_SET_ELEMENT_TEXT could be used as otherwise the dialog
// layout becomes completely mangled (at least under Windows 7).
::SendMessage( hwnd,
TDM_SET_ELEMENT_TEXT,
TDM_UPDATE_ELEMENT_TEXT,
TDE_EXPANDED_INFORMATION,
wxMSW_CONV_LPARAM(expandedInformation) );
}
@ -777,8 +806,9 @@ bool wxProgressDialog::Show(bool show)
wxPD_ESTIMATED_TIME |
wxPD_REMAINING_TIME) )
{
// Use a non-empty string just to have the collapsible pane shown.
m_sharedData->m_expandedInformation = " ";
// Set the expanded information field from the beginning to avoid
// having to re-layout the dialog later when it changes.
UpdateExpandedInformation(0);
}
// Do launch the thread.
@ -887,9 +917,6 @@ void* wxProgressDialogTaskRunner::Entry()
tdc.pfCallback = TaskDialogCallbackProc;
tdc.lpCallbackData = (LONG_PTR) &m_sharedData;
// Undo some of the effects of MSWCommonTaskDialogInit().
tdc.dwFlags &= ~TDF_EXPAND_FOOTER_AREA; // Expand in content area.
if ( m_sharedData.m_style & wxPD_CAN_SKIP )
wxTdc.AddTaskDialogButton( tdc, Id_SkipBtn, 0, _("Skip") );