Worked around an apparent bug in Windows whereby some deferred positioning

failed: specifically when changing a position from x, to y, to x again.
Added deferred positioning to wxRadioBox, wxSlider and wxSpinCtrl and thereby
eliminated some refresh glitches when resizing.
Eliminated further refresh glitches caused by wxRadioBox (to nearby controls)
by refreshing parent when the radio box moves.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@33907 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2005-04-28 14:45:09 +00:00
parent 2b822a7e06
commit 8e44f3caab
8 changed files with 230 additions and 40 deletions

View File

@@ -11,7 +11,16 @@ All:
wxMSW:
- Fixed erroneous selection of content in wxComboBox when within a wxStaticBox.
- Fixed erroneous selection of content in wxComboBox when within a wxStaticBox
(checking for selection caused by WM_STYLECHANGED).
- Worked around an apparent bug in Windows whereby some deferred positioning
failed: specifically when changing a position from x, to y, to x again.
- Added deferred positioning to wxRadioBox, wxSlider and wxSpinCtrl and thereby
eliminated some refresh glitches when resizing.
- Eliminated further refresh glitches caused by wxRadioBox (to nearby controls)
by refreshing parent when the radio box moves.
- Added ability set the system option "msw.staticbox.optimized-paint" to 0 to
allow a panel to paint graphics around controls within a static box.
wxMac:

View File

@@ -28,6 +28,9 @@ pages).}
\twocolitem{msw.staticbitmap.htclient}{If set to 1, allows the static bitmap to respond to mouse
events. The default is 0, since a value of 1 can interfere with refresh in static boxes. Note that once set,
this option cannot be unset later in the application.}
\twocolitem{msw.staticbox.optimized-paint}{If set to 0, switches off optimized wxStaticBox painting.
Setting this to 0 causes more flicker, but allows applications to paint graphics on the parent of a static box
(the optimized refresh causes any such drawing to disappear).}
\end{twocollist}
\wxheading{Mac}

View File

@@ -701,6 +701,9 @@ inline bool wxStyleHasBorder(long style)
wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0;
}
// Deferred window moving
bool wxMoveWindowDeferred(HDWP& hdwp, wxWindow* win, HWND hWnd, int x, int y, int width, int height);
// ----------------------------------------------------------------------------
// functions mapping HWND to wxWindow
// ----------------------------------------------------------------------------

View File

@@ -47,6 +47,9 @@ enum
class WXDLLEXPORT wxWindowMSW : public wxWindowBase
{
friend class wxSpinCtrl;
friend class wxSlider;
friend class wxRadioBox;
public:
wxWindowMSW() { Init(); }
@@ -541,5 +544,17 @@ WX_DECLARE_HASH(wxWindowMSW, wxWindowList, wxWinHashTable);
extern wxWinHashTable *wxWinHandleHash;
// ----------------------------------------------------------------------------
// extra data needed for correcting problems with deferred positioning
// ----------------------------------------------------------------------------
struct wxExtraWindowData
{
// Stored during deferred positioning
wxPoint m_pos;
wxSize m_size;
bool m_deferring:1;
};
#endif
// _WX_WINDOW_H_

View File

@@ -40,6 +40,8 @@
#include "wx/msw/subwin.h"
#define USE_DEFERRED_SIZING 1
#if wxUSE_TOOLTIPS
#if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
#include <commctrl.h>
@@ -545,7 +547,17 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
height = heightOld;
}
::MoveWindow(GetHwnd(), xx, yy, width, height, TRUE);
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
wxWindowMSW *parent = GetParent();
#if USE_DEFERRED_SIZING
HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
#else
HDWP hdwp = 0;
#endif
wxMoveWindowDeferred(hdwp, this, GetHwnd(), xx, yy, width, height);
// Now position all the buttons: the current button will be put at
// wxPoint(x_offset, y_offset) and the new row/column will start at
@@ -642,6 +654,22 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
x_offset += widthBtn + cx1;
}
}
if (hdwp)
{
// Store the size so we can report it accurately
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (!extraData)
{
extraData = new wxExtraWindowData;
m_windowReserved = (void*) extraData;
}
extraData->m_pos = wxPoint(xx, yy);
extraData->m_size = wxSize(width, height);
extraData->m_deferring = true;
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
}
// ----------------------------------------------------------------------------
@@ -687,6 +715,17 @@ wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
return 0;
}
// FIXME: Without this, the radiobox corrupts other controls as it moves
// in a dynamic layout. Refreshing causes flicker, but it's better than
// leaving droppings. Note that for some reason, wxStaticBox doesn't need
// this (perhaps because it has no real children?)
else if (nMsg == WM_MOVE && IsKindOf(CLASSINFO(wxRadioBox)))
{
WXLRESULT res = wxControl::MSWWindowProc(nMsg, wParam, lParam);
wxRect rect = GetRect();
GetParent()->Refresh(true, & rect);
return res;
}
return wxStaticBox::MSWWindowProc(nMsg, wParam, lParam);
}

View File

@@ -42,6 +42,8 @@
#include <commctrl.h>
#endif
#define USE_DEFERRED_SIZING 1
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
@@ -441,6 +443,16 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height)
return;
}
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
wxWindowMSW *parent = GetParent();
#if USE_DEFERRED_SIZING
HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
#else
HDWP hdwp = 0;
#endif
// be careful to position the slider itself after moving the labels as
// otherwise our GetBoundingBox(), which is called from WM_SIZE handler,
// would return a wrong result and wrong size would be cached internally
@@ -453,22 +465,21 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height)
// position all labels: min at the top, value in the middle and max at
// the bottom
::MoveWindow((*m_labels)[SliderLabel_Min],
xLabel, y, wLabel, hLabel, TRUE);
wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Min],
xLabel, y, wLabel, hLabel);
::MoveWindow((*m_labels)[SliderLabel_Value],
xLabel, y + (height - hLabel)/2, wLabel, hLabel, TRUE);
wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Value],
xLabel, y + (height - hLabel)/2, wLabel, hLabel);
::MoveWindow((*m_labels)[SliderLabel_Max],
xLabel, y + height - hLabel, wLabel, hLabel, TRUE);
wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Max],
xLabel, y + height - hLabel, wLabel, hLabel);
// position the slider itself along the left/right edge
::MoveWindow(GetHwnd(),
wxMoveWindowDeferred(hdwp, this, GetHwnd(),
HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
y + hLabel/2,
width - wLabel - HGAP,
height - hLabel,
TRUE);
height - hLabel);
}
else // horizontal
{
@@ -479,22 +490,37 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height)
// position all labels: min on the left, value in the middle and max to
// the right
::MoveWindow((*m_labels)[SliderLabel_Min],
x, yLabel, wLabel, hLabel, TRUE);
wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Min],
x, yLabel, wLabel, hLabel);
::MoveWindow((*m_labels)[SliderLabel_Value],
x + (width - wLabel)/2, yLabel, wLabel, hLabel, TRUE);
wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Value],
x + (width - wLabel)/2, yLabel, wLabel, hLabel);
::MoveWindow((*m_labels)[SliderLabel_Max],
x + width - wLabel, yLabel, wLabel, hLabel, TRUE);
wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Max],
x + width - wLabel, yLabel, wLabel, hLabel);
// position the slider itself along the top/bottom edge
::MoveWindow(GetHwnd(),
wxMoveWindowDeferred(hdwp, this, GetHwnd(),
x,
HasFlag(wxSL_TOP) ? y : y + hLabel,
width,
height - hLabel,
TRUE);
height - hLabel);
}
if ( hdwp )
{
// Store the size so we can report it accurately
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (!extraData)
{
extraData = new wxExtraWindowData;
m_windowReserved = (void*) extraData;
}
extraData->m_pos = wxPoint(x, y);
extraData->m_size = wxSize(width, height);
extraData->m_deferring = true;
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
}

View File

@@ -45,6 +45,8 @@
#include <limits.h> // for INT_MIN
#define USE_DEFERRED_SIZING 1
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
@@ -567,21 +569,55 @@ void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
wxLogDebug(_T("not enough space for wxSpinCtrl!"));
}
if ( !::MoveWindow(GetBuddyHwnd(), x, y, widthText, height, TRUE) )
{
wxLogLastError(wxT("MoveWindow(buddy)"));
}
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
wxWindowMSW *parent = GetParent();
int originalX = x;
#if USE_DEFERRED_SIZING
HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
#else
HDWP hdwp = 0;
#endif
// 1) The buddy window
wxMoveWindowDeferred(hdwp, this, GetBuddyHwnd(),
x, y, widthText, height);
// 2) The button window
x += widthText + MARGIN_BETWEEN;
if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) )
wxMoveWindowDeferred(hdwp, this, GetHwnd(),
x, y, widthBtn, height);
if (hdwp)
{
wxLogLastError(wxT("MoveWindow"));
// Store the size so we can report it accurately
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (!extraData)
{
extraData = new wxExtraWindowData;
m_windowReserved = (void*) extraData;
}
extraData->m_pos = wxPoint(originalX, y);
extraData->m_size = wxSize(width, height);
extraData->m_deferring = true;
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
}
// get total size of the control
void wxSpinCtrl::DoGetSize(int *x, int *y) const
{
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
{
*x = extraData->m_size.x;
*y = extraData->m_size.y;
return;
}
RECT spinrect, textrect, ctrlrect;
GetWindowRect(GetHwnd(), &spinrect);
GetWindowRect(GetBuddyHwnd(), &textrect);
@@ -595,6 +631,14 @@ void wxSpinCtrl::DoGetSize(int *x, int *y) const
void wxSpinCtrl::DoGetPosition(int *x, int *y) const
{
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
{
*x = extraData->m_pos.x;
*y = extraData->m_pos.y;
return;
}
// hack: pretend that our HWND is the text control just for a moment
WXHWND hWnd = GetHWND();
wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hwndBuddy;

View File

@@ -119,6 +119,8 @@
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
#define USE_DEFERRED_SIZING 1
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
@@ -468,6 +470,12 @@ wxWindowMSW::~wxWindowMSW()
{
m_isBeingDeleted = true;
if (m_windowReserved)
{
delete (wxExtraWindowData*) m_windowReserved;
m_windowReserved = NULL;
}
#ifndef __WXUNIVERSAL__
// VS: make sure there's no wxFrame with last focus set to us:
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
@@ -1443,6 +1451,14 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
{
*x = extraData->m_size.x;
*y = extraData->m_size.y;
return;
}
RECT rect = wxGetWindowRect(GetHwnd());
if ( x )
@@ -1454,6 +1470,14 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const
// Get size *available for subwindows* i.e. excluding menu bar etc.
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
{
*x = extraData->m_pos.x;
*y = extraData->m_pos.y;
return;
}
RECT rect = wxGetClientRect(GetHwnd());
if ( x )
@@ -1546,29 +1570,31 @@ void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
wxWindowMSW *parent = GetParent();
#if USE_DEFERRED_SIZING
HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
#else
HDWP hdwp = 0;
#endif
wxMoveWindowDeferred(hdwp, this, GetHwnd(), x, y, width, height);
if ( hdwp )
{
hdwp = ::DeferWindowPos(hdwp, GetHwnd(), NULL,
x, y, width, height,
SWP_NOZORDER);
if ( !hdwp )
// Store the size so we can report it accurately
wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
if (!extraData)
{
wxLogLastError(_T("DeferWindowPos"));
extraData = new wxExtraWindowData;
m_windowReserved = (void*) extraData;
}
extraData->m_pos = wxPoint(x, y);
extraData->m_size = wxSize(width, height);
extraData->m_deferring = true;
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
// otherwise (or if deferring failed) move the window in place immediately
if ( !hdwp )
{
if ( !::MoveWindow(GetHwnd(), x, y, width, height, IsShown()) )
{
wxLogLastError(wxT("MoveWindow"));
}
}
}
// set the size of the window: if the dimensions are positive, just use them,
@@ -5931,6 +5957,31 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
#endif // wxUSE_HOTKEY
// Moves a window by deferred method or normal method
bool wxMoveWindowDeferred(HDWP& hdwp, wxWindow* win, HWND hWnd, int x, int y, int width, int height)
{
if ( hdwp )
{
hdwp = ::DeferWindowPos(hdwp, hWnd, NULL,
x, y, width, height,
SWP_NOZORDER);
if ( !hdwp )
{
wxLogLastError(_T("DeferWindowPos"));
}
}
// otherwise (or if deferring failed) move the window in place immediately
if ( !hdwp )
{
if ( !::MoveWindow(hWnd, x, y, width, height, win->IsShown()) )
{
wxLogLastError(wxT("MoveWindow"));
}
}
return hdwp != NULL;
}
// Not tested under WinCE
#ifndef __WXWINCE__