• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3785
  • Last Modified:

flickering in dialog controls

Hi,
i have a CDialog "CMainDlg" with a CTabCtrl. The CTabCtrl "m_tabCtrl" creates some pages with borderless dialog templates from the resources in CMainDlg::OnInitDialog(), named "m_cPg1".."m_cPg4"

I implemented automatic window-fitting of the controls by OnSize() Handler of the CMainDlg

Problem: the controls flicker strong while sizing (e.g. a CListControl on the CTabCtrl).

- please see code below
- how to resize the controls without flickering ? They should be resized flicker-free while moving.(Other win apps can do that)
- a simple ClistControl on the CMainDlg (without a CTabcontrol) does also flicker.
- I read about a memory dc, which can be used for flicker free custom painting in OnEraseBknd() handler. But I need no extra painting (e.g. a CBitmap) that would require a dc. I only need to resize dialog controls! Do I need to use buffering technique ?

Thanks very much!
void CMainDlg::OnSize(UINT nType, int cx, int cy)
{
          // comment out or leave, put at top or at end: has no visual effect!!
//        CDialog::OnSize(nType, cx, cy); 

         // fit control windows to new size:
         // (using FALSE means telling Windows that no repaint is required immediately.)

           m_tabctrl.MoveWindow(10, 10, cx-20, cy-60, FALSE);

           // now resize the dialog windows of the tab control, do only for visible tab
           CRect r;
           m_tabctrl.GetClientRect(&r);
           
           switch(m_tabctrl.GetCurSel())
		{
		case 0:
			m_cPg1.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
			break;
		
		case 1:
			m_cPg2.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
			break;

		case 2:
			m_cPg3.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
			break;

		case 3:
			m_cPg4.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
			break;
		} // end switch
}

void CSubDlg::Onsize(UINT nType, int cx, int cy)
{
      // comment out or leave, put at top or at end: has no visual effect!!
      CDialog::OnSize(nType, cx, cy);

      // fit clistctrl member to new size
      ...
      m_list.MoveWindow	(x2,	y1,	sx2,	y_area,	FALSE); // the list control flickers
}

Open in new window

0
stev75
Asked:
stev75
  • 9
  • 7
  • 3
  • +1
3 Solutions
 
AndyAinscowCommented:
Does this help

void CMainDlg::OnSize(UINT nType, int cx, int cy)
{
LockWindowUpdate();

          // comment out or leave, put at top or at end: has no visual effect!!
//        CDialog::OnSize(nType, cx, cy);

         // fit control windows to new size:
         // (using FALSE means telling Windows that no repaint is required immediately.)

           m_tabctrl.MoveWindow(10, 10, cx-20, cy-60, FALSE);

           // now resize the dialog windows of the tab control, do only for visible tab
           CRect r;
           m_tabctrl.GetClientRect(&r);
           
           switch(m_tabctrl.GetCurSel())
                {
                case 0:
                        m_cPg1.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
                        break;
               
                case 1:
                        m_cPg2.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
                        break;

                case 2:
                        m_cPg3.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
                        break;

                case 3:
                        m_cPg4.MoveWindow(20, 50, r.Size().cx-20, r.Size().cy-50, FALSE);
                        break;
                } // end switch

UnlockWindowUpdate();
}

0
 
stev75Author Commented:
hello AndyAinscow,
this even causes the desktop to flicker (!) . seems to be a system wide setting...  Thx
0
 
AndyAinscowCommented:
This is not a system wide setting.


From help files.

CWnd::LockWindowUpdate  


Disables drawing in the given window.

 
BOOL LockWindowUpdate( );
 

Return Value
Nonzero if the function is successful. It is 0 if a failure occurs or if the LockWindowUpdate function has been used to lock another window.

Remarks
A locked window cannot be moved. Only one window can be locked at a time. To unlock a window locked with LockWindowUpdate, call UnlockWindowUpdate.

If an application with a locked window (or any locked child windows) calls the GetDC, GetDCEx, or BeginPaint Windows function, the called function returns a device context whose visible region is empty. This will occur until the application unlocks the window by calling the UnlockWindowUpdate member function.

While window updates are locked, the system keeps track of the bounding rectangle of any drawing operations to device contexts associated with a locked window. When drawing is reenabled, this bounding rectangle is invalidated in the locked window and its child windows to force an eventual WM_PAINT message to update the screen. If no drawing has occurred while the window updates were locked, no area is invalidated.

The LockWindowUpdate member function does not make the given window invisible and does not clear the WS_VISIBLE style bit.
0
Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

 
stev75Author Commented:
Good. i will experiment where to place this function and check if it makes sense using it. It is obviously wrong to place it in OnSize() handler.
0
 
pgnatyukCommented:
I'm trying to add something to the AndyAinscow's comment (thanks, I forgot about this method).

You really can use WM_ERASEBKGRND message. It will help a bit. We are talking about the MFC app, so just add this method to the parent window and it should have just one line - return TRUE;. You can try FALSE if you wish. You need to check all Invalidate calls in your app and do not call it more then you really need (actually Andy's comment blocks exactly that).

I remembered only SetRedraw method:
http://msdn.microsoft.com/en-us/library/btaacw58(VS.80).aspx
You will an example there that really works with the controls - when you need to update a list, for example.

All other things you mentioned about the memory DC will have if you draw images and text - you make an internal DC, put all images on it and within OnPaint just call BitBlt from this already prepared internal DC to the window DC.

http://www.codeproject.com/KB/GDI/flickerfree.aspx
http://www.experts-exchange.com/Q_10190215.html
0
 
AndyAinscowCommented:
Handling the WM_ERASEBKGROUND message is a standard way for helping in the flicker free drawing of a window.  But I think it would have to be implemented for each child window separately as well - because each of those has a background.
0
 
stev75Author Commented:
A possible solution would be to use MoveWindow(..., TRUE) for each single dialog control in >>OnSize(..)
 Then it does not flicker, but
When Szing, this is causing small painting errors. Reason> depending on the order the controls get redrawn, overlapping
So a good flicker-free redraw while sizing requires to define the Redraw-Order for the control depending on the sizing direction (!)
Alternativly, you could use WM_EXITSIZEMOVE, to ensure correct redraw after sizing, or
call Invalidate() on just the dialog control, that can be overlapped by others. That will repaint the area of the control.
 
0
 
ZoppoCommented:
Hi stev75,

IMO you should try a similar approach as AndyAinscow suggested, but instead of using LockWindowUpdate/UnlockWindowUpdate you should use 'SetRedraw' (MSDN states about LockWindowUpdate: LockWindowUpdate is not intended for general-purpose suppression of window redraw. Use the WM_SETREDRAW message to disable redrawing of a particular window).

So, try something like this:

> void CMainDlg::OnSize(UINT nType, int cx, int cy)
> {
>   SetRedraw( FALSE );
>
>   // your code
>   ...
>
>   SetRedraw( TRUE );
>
>   Invalidate( TRUE );
> }

Hope that helps,

ZOPPO
0
 
ZoppoCommented:
Ah, sorry, pgnatyuk, I just noticed you already mentioned the 'SetRedraw' ...
0
 
AndyAinscowCommented:
My understanding of SetRedraw is that it is specific to a window.  
What happens to child windows is not stated, also examples (MSDN) explicitly are used with a child window such as a list control when adding multiple items in one block of code.
0
 
AndyAinscowCommented:
One other point.
You are using MoveWindow(...., FALSE) - the FALSE should suppress any and all repainting of the window.
ie. You should not be getting any flicker from the OnSize routine.

How are you causing the dialog (and child windows) to be redrawn ?
0
 
stev75Author Commented:
Hi AndyAinscow
You are right, I detected A "RedrawWindow()" in the source code.
The RedrawWindow() is used to prevent any overlapping behaviour, but it causes flickering.
Please note that the intention is about having smooth control-resizing  while the window is resizing. I don't want to turn of drawing while sizing.
@Zoppo
An Invalidate() on the whole dialog will possibly cause flickering again, because all areas are repainted, not only the controls.
(for the case when It's used in OnSize(), which is called every mouse dragging move.)
It seems that when moving the mouse quick (while sizing the window), some of the "invalidation areas" have become out of date.
An old invalidation area leads to reapint errors. These are only seen on the controls (e.g. buttons), not on the empty CDialog area. If you call Invalidate just for the buttons, it seems OK!
example>
...OnSize(..) {
pBtn->MoveWindow(..., TRUE) // still possible overlapping error on quick window resizing
pBtn->Invalidate() // call additionally> the whole button gets repainted by the system AFTER the other stuff, which is fine! (A single button redraw doesn't show flickering)
}
 
 
0
 
pgnatyukCommented:
stev75, I think we will understand more and will help more if we will know what is the window we are talking about and what are the child windows there. Is it a standard dialog with many buttons? No images in the background?

For this case we may use one method and for a complex image drawn in your window we need to use another method. Last case can be solved even logically without a special Windows messages.

>>pBtn->Invalidate()
I do not understand why you need that. Anyway it is a child window. The parent window has WS_CLIPCHILDREN style, so this window will be redrawn automatically. Please check it too.

0
 
AndyAinscowCommented:
Is the RedrawWindow being called multiple times for each size/move event?


ps. I hope the child dialogs (m_cPg1....) are being hidden when not required, else one is drawn, then another on top of the first, then another on top of the second .....  < welcome to flickerland ! >
0
 
stev75Author Commented:
there are no extra images drawn, you can reproduce the overlapping painting error>
 you have 2 CButtons on a resizable CDialog (THICKFRAME style etc), created in resource editor.
Now you want these 2 buttons (which are commonly "Cancel" and "OK") always stick to the right dialog border, no matter what the CDialog size is.
CButton* pBtn = (CButton*)GetDlgItem(IDC_BUTTON1)
so you adjust each button
pBtn1->with MoveWindow(..)
pBtn2->with MoveWindow(..) in Onsize().
>> The one button1 that is drawn BEFORE button2 CAN get repaint errors when QUICK (== BIG size change) Window resizing is performed with the mouse.
reason is the other pBtn2->MoveWindow().
 
0
 
stev75Author Commented:
... and when you call pBtn1->Invalidate() no repaint problem will occur on the button1.
@Andy, RedrawWindow is not a good function. Removed it completely.
So pControl->MoveWindow and pControl->Invalidate is a good pair !!
0
 
pgnatyukCommented:
So simple case?
In the resource editor you can set anchors for this two buttons. Probably, that's it.
0
 
stev75Author Commented:
found the solution mainly by myself
0
 
AndyAinscowCommented:
Just to be pedantic I did not recommend using RedrawWindow.

ps. I bet you used the default arguments == redraw the window NOW.  So multiple redraws would have been being performed during the resizing operation in most cases (see my last comment).
0
 
stev75Author Commented:
HI,
I
0
 
stev75Author Commented:
... That's right - using RedrawWindow is not the best way in MFC message handling, If you do so, you have to "validate" the draw regions again , otherwise it will flicker.
drawing just  the portions that can have small errors (due to sizing action) is a compromise here.
0

Featured Post

NEW Veeam Backup for Microsoft Office 365 1.5

With Office 365, it’s your data and your responsibility to protect it. NEW Veeam Backup for Microsoft Office 365 eliminates the risk of losing access to your Office 365 data.

  • 9
  • 7
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now