General Flicker Free Resizable Control

Oh no, yet another resizable dialog class! This is what you might think, but I have looked at several solutions for resizable dialogs, but neither of them met my requirements; so like all the others, I decided to make my own class. Some of the advantages in this solution:
  • General solution, can be used in dialogs, form views, property sheets, etc.
  • Possible to split added size between several controls.
  • Not necessary to declare all controls with DDX_Control.
  • Flicker Free implementation (that also works with group boxes).
  • Easy setting of the sizing options though several different interfaces.
  • Possible to save window placement in registry.
  • Small and simple implementation.

The solution is not a CDialog derived class, but a generic class (CResize) that can be used in other situations as well. It is applied to the dialog (CResizeDialog), property page and sheet (CResizePropertyPage and CResizePropertySheet), and form view (CResizeFormView) classes. The demo project shows how to use the class in these four situations. Notice that the property sheet demo shows how to include minimize and maximize buttons.

Throughout the remaining part of this document, I will assume that the control is applied to a dialog class.

Resize Paradigm

The resize paradigm is to specify how much each side of a control will move when the dialog is resized. If a control should be repositioned (e.g. an OK button) then all four sides should move with the same amount of pixels as the dialog is resized. If a control should be resized just as much as the dialog (e.g. the list control in the file dialog), then the left and top sides shouldn't move, and the right and bottom sides should move with the same amount of pixels as the dialog.

In this example the added horizontal size should be split between the two edit boxes, and the added vertical size should be consumed by the two edit controls. The sides of the edit controls move as shown on the image.

The sizing for the two edit controls can be set in these four different, but functional equal, ways:

// sizing set using array of items
static SIZING s_arrSizing[] =
{ 
 //  identifier   left  top   right bottom
 IDC_EDIT1,   0,    0,    0.5,  1,
 IDC_EDIT2,   0.5,  0,    1,    1
};
SetResize(s_arrSizing); 

// sizing set directly with functions
SetResize(IDC_EDIT1, 0,   0,   0.5, 1);
SetResize(IDC_EDIT2, 0.5, 0,   1,   1);

// sizing set with functions using added macros
SetResize(IDC_EDIT1, SZ_HORRESIZE(0.5) 
                     + SZ_VERRESIZE(1));

SetResize(IDC_EDIT2, SZ_HORRESIZE(0.5) 
                     + SZ_HORREPOS(0.5) 
                     + SZ_VERRESIZE(1));

// sizing set with multiple functions using macros
SetResize(IDC_EDIT1, SZ_HORRESIZE(0.5));
SetResize(IDC_EDIT1, SZ_VERRESIZE(1));
SetResize(IDC_EDIT2, SZ_HORRESIZE(0.5));
SetResize(IDC_EDIT2, SZ_HORREPOS(0.5));
SetResize(IDC_EDIT2, SZ_VERRESIZE(1));
The available macros for the definitions are:

SZ_RESIZE(x)    // resize
SZ_REPOS(x)     // reposition
SZ_HORRESIZE(x) // horizontal resize
SZ_HORREPOS(x)  // horizontal reposition
SZ_VERRESIZE(x) // vertical resize
SZ_VERREPOS(x)  // vertical reposition

The values of x must be in the range [0,1], which is verified with assertions.

Notice that the only thing you have to do to implement a resizable dialog, is to derived your own dialog class from CResizeDialog instead of CDialog, and set the sizing options as shown above.

Flickering

The windows style WS_CLIPCHILDREN needs to be set to prevent the dialog from flickering. This causes a problem for group boxes (wrong window painting in the area of the group box), but that can be solved by making the group boxes transparent (they still flicker though). The CResize class automatically sets the WS_CLIPCHILDREN style for the dialog and the WS_EX_TRANSPARENT extended style for the group boxes to cope with these problems (this can be disabled by setting the corresponding flags, see the next section).

Notice that the tabs of the property pages still flicker, I haven't found a way to solve that (yet).

Flags

The following flags are defined to control the behavior:

SZ_NOSIZEICON         // do not add size icon
SZ_NOHORISONTAL       // no horizontal resizing
SZ_NOVERTICAL         // no vertical resizing
SZ_NOMINSIZE          // do not require a minimum size
SZ_NOCLIPCHILDREN     // do not set clip children style
SZ_NOTRANSPARENTGROUP // do not set transparent style for group boxes

The flags are set through the last argument of the constructors.

Minimum Size

The default minimum size is the initial size of the dialog, which can be overruled by the flag SZ_NOMINSIZE or by setting the size explicitly with the function SetMinSize. You can set a maximum size as well.

// set the minimum size explicitly (initial size is the default)
void SetMinSize(CSize& sz);

// set the maximum (no maximum as default)
void SetMaxSize(CSize& sz);

Storing the last used Window Placement

The size of the dialog can be saved to and loaded from the registry, which is shown for the demo dialog in the demo project.

// save window placement to registry
void SavePlacement(LPCTSTR pszSection); 

// load saved window placement from registry
void LoadPlacement(LPCTSTR pszSection); 

Downloads

Download source - 7 KB
Download demo project - 39 KB (including this page)


Comments

  • Those things everyone else actually does concerning nike and moreover exactly what you'll need to handle completely different.

    Posted by icoppyapedcap on 04/23/2013 12:16am

    LvoBfqQmaMxj [url=http://www.adidasgekiyasu.biz/]アディダス[/url]YbrXdhMzvCzd [url=http://www.nikegekiyasu.biz/]ナイキスニーカー[/url]KadFznGwvQtn FfyVxgCkjSpu[url=http://www.guccisayihujp.biz/]グッチ[/url]RdlBjdEomZlg [url=http://www.guccisayihujp.biz/【グッチ】レディース財布-c-5.html]gucci 財布[/url]PqsFxrAveCiw [url=http://www.guccisayihujp.biz/【グッチ】レディース長財布-c-6.html]gucci キーケース[/url]BcuYewVduVlv [url=http://www.guccisayihujp.biz/【グッチ】ショルダーバッグ-c-2.html]グッチ アウトレット[/url]UyhEsdSikZbz UflBvaFzoCpc [url=http://www.chloesayihujp.biz/]クロエ 財布[/url] GdoRlxHofNaw [url=http://www.chloesayihujp.biz/クロエ-長財布-c-3.html]クロエ 長財布[/url] SnqJmeRtjPmn [url=http://www.chloesayihujp.biz/クロエ-ハンドバッグ-c-2.html]chloe バッグ[/url] YzdIxmJvgRwb PpiMbtZvlKpq [url=http://www.chanelsayihujp.biz/]chanel[/url] RzbFvxRfcUym [url=http://www.chanelsayihujp.biz/シャネル財布-c-9.html]シャネル 財布 新作[/url]NcmWmcGhlQmj [url=http://www.chanelsayihujp.biz/シャネル-ショルダーバッグ-c-1.html]chanel bag[/url]FxlKylYbcVoc

    Reply
  • Bug in SetResize(SIZING arr[])

    Posted by funster10 on 09/21/2005 02:44pm

    The number of elements in arr[] is incorrectly calculated. You need to calculate it before calling like this:
       int count = sizeof(s_arrSizing) / sizeof(s_arrSizing[0]);
    Then pass in count as a 2nd parameter to SetResize() and use count to terminate the for() loop.

    Reply
  • Try CMemDC!

    Posted by Legacy on 10/23/2003 12:00am

    Originally posted by: Rudolf M�hlbauer

    you should try CMemDC to paint:
    
    

    #if !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
    #define AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_

    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // MemDC.h : header file
    //

    //////////////////////////////////////////////////
    // CMemDC - memory DC
    //
    // Author: Keith Rule
    // Email: keithr@europa.com
    // Copyright 1996-1997, Keith Rule
    //
    // You may freely use or modify this code provided this
    // Copyright is included in all derived versions.
    //
    // History - 10/3/97 Fixed scrolling bug.
    // Added print support.
    // 25 feb 98 - fixed minor assertion bug
    //
    // This class implements a memory Device Context

    class CMemDC : public CDC
    {
    public:

    // constructor sets up the memory DC
    CMemDC(CDC* pDC) : CDC()
    {
    ASSERT(pDC != NULL);

    m_pDC = pDC;
    m_pOldBitmap = NULL;
    #ifndef WCE_NO_PRINTING
    m_bMemDC = !pDC->IsPrinting();
    #else
    m_bMemDC = FALSE;
    #endif

    if (m_bMemDC) // Create a Memory DC
    {
    pDC->GetClipBox(&m_rect);
    CreateCompatibleDC(pDC);
    m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
    m_pOldBitmap = SelectObject(&m_bitmap);
    #ifndef _WIN32_WCE
    SetWindowOrg(m_rect.left, m_rect.top);
    #endif
    // EFW - Bug fix - Fill background in case the user has overridden
    // WM_ERASEBKGND. We end up with garbage otherwise.
    // CJM - moved to fix a bug in the fix.
    FillSolidRect(m_rect, pDC->GetBkColor());
    }
    else // Make a copy of the relevent parts of the current DC for printing
    {
    #if !defined(_WIN32_WCE) || ((_WIN32_WCE > 201) && !defined(WCE_NO_PRINTING))
    m_bPrinting = pDC->m_bPrinting;
    #endif
    m_hDC = pDC->m_hDC;
    m_hAttribDC = pDC->m_hAttribDC;
    }

    }

    // Destructor copies the contents of the mem DC to the original DC
    ~CMemDC()
    {
    if (m_bMemDC)
    {
    // Copy the offscreen bitmap onto the screen.
    m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
    this, m_rect.left, m_rect.top, SRCCOPY);

    //Swap back the original bitmap.
    SelectObject(m_pOldBitmap);
    } else {
    // All we need to do is replace the DC with an illegal value,
    // this keeps us from accidently deleting the handles associated with
    // the CDC that was passed to the constructor.
    m_hDC = m_hAttribDC = NULL;
    }
    }

    // Allow usage as a pointer
    CMemDC* operator->() {return this;}

    // Allow usage as a pointer
    operator CMemDC*() {return this;}

    private:
    CBitmap m_bitmap; // Offscreen bitmap
    CBitmap* m_pOldBitmap; // bitmap originally found in CMemDC
    CDC* m_pDC; // Saves CDC passed in constructor
    CRect m_rect; // Rectangle of drawing area.
    BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
    };

    /////////////////////////////////////////////////////////////////////////////

    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.

    #endif // !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)

    Reply
  • Progress control is still flickering with this class

    Posted by Legacy on 10/03/2003 12:00am

    Originally posted by: Hover

    The class works well on most environments. However, when I add a progress control bar in the dialogbox, and fill the progress control bar, it is still flickering seriously. How does this come?

    Reply
  • Group box flicker - solution

    Posted by Legacy on 05/03/2003 12:00am

    Originally posted by: Toomas

    The problem with group box redraw in a dialog with WS_CLIPCHILDREN tortured me three evenings. The transparent style didn't help me much, since it causes horrible flickering. I was trying to find any article on it, but only this page gave me at least some information. As Frank Litcher mentioned, it can be solved by ovewriting the WM_ERASEBKGDN. 
    
    

    I started in that point and it proved to be worthy. The solution is however not very easy, at least for beginners. My code is maybe not the best, but it works. It uses MFC, but the principles can be used by SDK programmers as well.

    BOOL CGroupBox::OnEraseBkgnd(CDC* pDC)
    {
    // Create a brush used for painting.
    // A system colour is used, however you can set it to anything suitable
    CBrush newBr;
    newBr.CreateSolidBrush(GetSysColor(COLOR_3DFACE));
    CBrush * oldBr = pDC->SelectObject(&newBr);

    // Create a background-colored pen to draw the rectangle borders
    CPen newPen;
    newPen.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DFACE));
    CPen * oldPen = pDC->SelectObject(&newPen);

    // Retrieve information about the client area.
    CRect rect;
    GetClientRect(&rect);

    // The group box is composed of three parts - label, frame and background
    // Only the background should be redrawn. It means, that we have to
    // determine the label and frame position and exclude these areas from
    // redrawing.

    // Get the label size
    CString str;
    GetWindowText(str);
    CFont * pFnt=this->GetFont();
    CFont * def_font = pDC->SelectObject(pFnt);
    CSize sz=pDC->GetTextExtent(str);
    pDC->SelectObject(def_font);


    // Erase the main area (inside the frame and under the label)
    CRect urect=rect; // Rectangle to update
    urect.left+=2;
    urect.right-=2;
    urect.bottom-=2;
    urect.top+=sz.cy+2;
    pDC->Rectangle(urect);


    // Erase the area around the label
    // Upper left
    urect.left=rect.left;
    urect.top=rect.top;
    urect.bottom=rect.top+sz.cy/2;
    urect.right=rect.left+7;
    pDC->Rectangle(urect);

    // Upper right corner
    urect.left=rect.left+11+sz.cx;
    urect.right=rect.right;
    pDC->Rectangle(urect);

    // Lower rigt corner
    urect.top=rect.top+sz.cy/2+2;
    urect.right-=2;
    urect.bottom=rect.top+sz.cy+2;
    pDC->Rectangle(urect);

    // Lower left corner
    urect.left=rect.left+2;
    urect.right=rect.left+7;
    pDC->Rectangle(urect);

    // Restore the original objects before releasing the DC.
    pDC->SelectObject(oldPen);
    pDC->SelectObject(oldBr);
    ReleaseDC(pDC);

    // Instruct Windows to paint the group box label and frame.
    InvalidateRect(&rect, FALSE);

    return TRUE; // Background has been erased.
    }

    It's also very important to add the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles to the group box to avoid further drawing and flickering problems (e.g. overwrite PreSubclassWindow if you like subclassing as I do).

    Reply
  • groupbox flick ,i have a stupid method

    Posted by Legacy on 04/29/2003 12:00am

    Originally posted by: xqyz8888

    I search ALL THE WORLD,NOT find out the method:preventing groupbox flick.i know the reason,i think you know too:the drawn area overlapped.
    i write some code to test .but i think,if i only need a beautiful serface ,i can use picture box and static to take place it.so i use four picture box and one static ,static as title.pic box as frame.set picbox property(in property dialog) :
    type as frame
    color as etched
    it's a too stupid method ,but it do better.never flick .then you can use clipchilder style .but you can not use groupbox 's group property.that's ok?

    Reply
  • Memory leak with Visual C++ .NET

    Posted by Legacy on 06/30/2002 12:00am

    Originally posted by: amauta

    Hello,

    I use this marvelous code in my programs, but when I complie with Visual C++ .NET, or Visual C++ 7.0 I have memory leaks, in function CResize::SetResize, one for dialog, and two for every control I want to resize.

    Does anyone kowns where is the problem?.

    Thanks in advance.

    Amauta.

    Reply
  • GroupBox flickering

    Posted by Legacy on 06/21/2002 12:00am

    Originally posted by: Frank Lichtner

    It's easy to prevent groupboxes from flickering. You have to subclass them and overwright the WM_ERASEBKGND message to delete the background. Don't set the tranparent flag for that groupbox.

    Frank

    Reply
  • CResize group box redraw issue...

    Posted by Legacy on 03/25/2002 12:00am

    Originally posted by: James E. Melter

    Great stuff but I found a
    groupbox related bug in BOOL CResize::Defer(HDWP hdwp, CItem* pItem, int dx, int dy) member fcn. The right side of the groupbox frame is sometimes not redrawn. I changed this line of code:

    if (DeferWindowPos(hdwp, hwnd, 0, x, y, cx, cy, SWP_NOZORDER) == 0)

    to this:

    if (DeferWindowPos(hdwp, hwnd, 0, x, y, cx, cy,
    SWP_SHOWWINDOW | SWP_DRAWFRAME | SWP_NOZORDER) == 0)

    and it seemed to correct the problem.

    I also still get "control location bounce" if I use the upper-left or lower-left window resizer handles to resize the window, Whazzup?

    Thanks.

    Reply
  • Well done! but maybe a mistake in 'CResize::SetResize(SIZING arr[])'

    Posted by Legacy on 12/09/2001 12:00am

    Originally posted by: Esoul

    inline void CResize::SetResize(SIZING arr[])
    
    {
    for (int i=0; i<sizeof(arr); i++)
    {
    SIZING& sz = arr[i];
    SetResize(sz.id, sz.rrc.left, sz.rrc.top, sz.rrc.right, sz.rrc.bottom);
    }
    }

    'sizeof(arr)' is equal to 'sizeof(SIZING*)' and it always gets 4. So SetResize(SIZING arr[]) can't add more than 4 items.

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today makes data protection a must-have, as we live in a data-driven society -- the digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join Seagate Cloud …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds