In my MFC application, I am doing a custom drawing in my dialog class OnPaint(). I have also created a few controls in dialog template. I have also resized and repositioned some of the controls in the dialog code. When I run my application, the controls are flickering.
Please suggest me how to avoid this?
CDC *pDC = GetDC(); //Get DC for Dialog's Client Area
pDCTmp->CreateCompatibleDC(pDC); //Create Compatible DC(pDCTmp) for Dialog's Client Area(pDC)
//pDCTmp is a member Variable
pBgBitmap->CreateCompatibleBitmap (pDC, 800, 640 ); //Create Compatible Bitmap(pBgBitmap) for Dialog's Client Area(pDC)
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
rect = rScreen; //rScreen is Client rect
pDCTmp->FillRect(rect,&CBrush(RGB(152, 185, 192))); //pDCTmp member variable is used to draw
//Custom drawings using the pDCTmp
A seperate thread function created already which calls a function UpdateAllViews() as shown below every half a second which in turn calls Invalidate the CFP Dialog. This is done to continuously update some real time numerical values on the dialog. When I remove this line
then there is no flickering on the dialog. But the values are not updated. How to avoid this flickering without affecting the value updation.
I'm a little confused by some of your code but generally I think you will
have to override WM_ERASEBKGND so that the background is not erased by the
default processing. Do not call the base class; just return TRUE.
1. Do you have to call Invalidate() from a thread? Could you use a timer in the dialog
and only update what is needed instead of invalidating the whole dialog?
2. Are your dialog controls embedded in a TabControl/TabPage? If so you will have to
create a custom TabControl and TabPage to override the OnEraseBackground() in those and
paint the background in a temp dc as well.
3. I'm not sure about this, but you may have to set the dialog style WS_CLIBCHILDREN to
include them in the dialogs clip region. Look at definition in msdn.
That means it doesn't paint the background before it sends you an WM_PAINT
If you want/need to transparent overlay the bitmap you have to use a transparent colour to stop flashing
CPaintDC dc(this); // device context for painting// transfer the bitmap into paint DC using a transparent color
10, 10, bmp.bmWidth, bmp.bmHeight, // destination coordinates and sizes
&pDCTmp, // source DC .. your DC with bitmap0, 0, bmp.bmWidth, bmp.bmHeight, // source coordinates and sizes
RGB(255, 0, 0)); // transparent color
I'm generating dialog templates programmatically for a win32 project. A thing I often want to do is size the dialog box such that the distance between the left edge of the client region and the left edge of the leftmost control is the same as that between the right edge of the rightmost control and the right edge of the client region. Since the size of the dialog box as specified in the template, I believe, includes the non-client area, the only way I know of to do this is to use AdjustWindowRect on a RECT representing the desired client region. Since this requires the handle of the window being adjusted, I can't do it until after the dialog has been created. So I was wondering...if I can't ensure equal margins until runtime, how is it possible that one can use the GUI editor Visual Studio provides to create dialogs with equal margins ahead of time? I want to be able to do that too.
You can select a set of controls in the editor and then use the toolbar tool that centres the group in the dialog. There are tools to centre horizontally or vertically, make equidistant, align together etc.
Resizing at runtime is what I'm currently doing, and it's an acceptable solution, but if possible I would like to specify the size of the dialog in the template, which is generated before runtime, such that it's correct relative to the controls it contains to begin with, without need of resizing. The fact that the dialog editor can do this suggests that it is indeed possible somehow.
I did something like this a long time ago where I defined a dialog within a code module without the
ui editor and I think you will have to implement the use of DLGTEMPLATE which is used to define the dialog and all of the associated controls.
Take a look at InitModalIndirect() in the Mfc library dlgcore.cpp and I believe
there was some needed functions in occmgr.cpp that will help to some extent.
If you haven't used this structure before, it will required a bit of work.
Oh yes, I'm still on V2005 so if you have the latest visual studio there may be some changes.
Hope this is what you are looking for.
A blank empty dialog template centred in it's parent at runtime and done the way speedbump is suggesting is coded below. It is pretty straight forward you just need to allocate global memory block as the template and you can fill the controls in at initialization
int DialogFromTemplate (HWND parent, int DialogWth, int DialogHt, char* DlgTitle, DLGPROC handler)
int nchar, ret;
int x, y;
GetClientRect(parent, &r); // Get parent client area
x = ((r.right+r.left)/2); // Calc x client centre position
y = ((r.bottom+r.top)/2); // Calc y client centre position/* from the client centre the dialog left is half width and top half height less */
x -= DialogWth/2;
y -= DialogHt/2;
/* template size and position are in multiples of 2 .. yeah its weird */
x /= 2; // X client left position in template units
y /= 2; // Y client top position in template units
hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024); // Allocate memoryif (!hgbl) return -1; // If allocate fail exit
lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); // Lock the allocated memory
lpdt->style = WS_POPUP | WS_CAPTION | WS_SYSMENU; // Window style
lpdt->cdit = 0; // Number of controls
lpdt->x = x; // X position
lpdt->y = y; // Y psoition
lpdt->cx = DialogWth/2; // Window width (template units)
lpdt->cy = DialogHt/2; // Window height (template units)
lpw = (LPWORD)(lpdt + 1); // Set pointer address
*lpw++ = 0; // No menu
*lpw++ = 0; // Predefined dialog box class (by default)
lpwsz = (LPWSTR)lpw; // Typecast pointer
nchar = 1 + MultiByteToWideChar(CP_ACP, 0, DlgTitle,
-1, lpwsz, 50); // Title of dialog
lpw += nchar; // Increment by size of name
*lpw++ = 0; // No creation data
GlobalUnlock(hgbl); // Release lock on the memory block
ret = (int)DialogBoxIndirectParam(GetModuleHandle(0),
(LPDLGTEMPLATE)hgbl, parent, Handler, 0); // Create the dialog from template
GlobalFree(hgbl); // Free the allocated memoryreturn ret; // Return result
Incorrect look at WM_INITDIALOG the message exists to do it. You simply move and resize the child windows before they become visible that is the whole point for the message to exist (read the message description). Everything is created but nothing has been drawn at that point. WM_INITDIALOG message - Windows applications | Microsoft Docs[^]
The OP didn't ask for that ... he asked for the ability to rescale a template or resource based dialog which we all do for high DPI apps because the inbuilt behaviour sucks.
Also for the record there are groups of controls that will do exactly what you have described they are called docking controls all you decide is where you want the anchor when you create them. I can easily give you a group of control that will automatically anchor themselves to the left side of a dialog it's trivial and CDockablePane in particular are often run that way in a dialog.
You can simply do a call to GetClientRect to get the parent area and change the dialog that is what the message is for. You can also use CreateDialogIndirectParam, CreateDialogParam, DialogBoxIndirectParam, or DialogBoxParam and pass
a pointer to the area or anything else you may want to do at runtime.
If you have not got access to the dialogs parent window handle you can get it by using the dialog handle with GetParent function | Microsoft Docs[^]
The dialog has been created and all functions on the handle work it just has not been made visible at that point.
You can also move and resize your child windows by handle or ID, they have all been created but nothing is visible at that point. You can also manually add child windows if you so desire at that point.
The WM_PAINT message to draw the dialog will be straight after that message and if it's a modal dialog it will then enter modal mode.
I am not sure how MFC encapsulates the WM_INITDIALOG probably ONINITDIALOG or something like that.
What I'm doing already is setting the using the size information in the dialog template to store the size I want the client region to be, then calling GetWindowRect, AdjustWindowRect, and MoveWindow from the WM_INITDIALOG implementation. From the answers I've gotten, it sounds like this is about the most direct solution I could hope for, which is good to know.
There are two parts to things positioning and scaling
Let me formally centre the dialog at runtime to it's parent in WM_INITDIALOG .. it is this simple
RECT R1, R2;
GetClientRect(GetParent(Wnd), &R1); // Parent client area
GetWindowRect(Wnd, &R2); // Dialog area
(R1.right+R1.left)/2 - (R2.right-R2.left)/2 , // Parent x centre - half dialog width
(R1.top+R1.Bottom)/2 - (R2.bottom-R2.top)/2, // Parent y centre - half dialog height0, 0, // No size data
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
Now if you want to centre and rescale generally you do the scale as a fraction to avoid floats
so (numerator/denominator) where denominator must not be zero
This usually works well because you have ( desired size / current size ) being the exact fraction
int Wth, Ht;
RECT R1, R2;
GetClientRect(GetParent(Wnd), &R1); // Parent client area
GetWindowRect(Wnd, &R2); // Dialog area
Wth = (R2.right-R2.left) * numerator; // Multiply dialog width by numerator
Wth /= denominator; // Divide dialog width by denominator
Ht = (R2.bottom-R2.top) * numerator; // Multiply dialog height by numerator
Ht /= denominator; // Divide dialog height by denominator
(R1.right+R1.left)/2 - Wth/2 , // Parent x centre - half scaled dialog width
(R1.top+R1.Bottom)/2 - Ht/2, // Parent y centre - half dialog height
Wth, Ht, // New sizes
SWP_NOACTIVATE | SWP_NOZORDER);// Do not change order or activate/* so if you want to scale the children windows you need to scale and move them *//* now go thru each child by id (shown as xxx) and scale and move them with this */
HWND cWnd = GetDlgItem(Wnd, xxxx); // Fetch and hold child handle from xxxx id
GetWindowRect(cWnd, &R3); // Fetch the child area
R3.left *= numerator; // Multiply child window left by numerator
R3.left /= denominator; // Divide child window left by denominator
R3.right *= numerator; // Multiply child window right by numerator
R3.right /= denominator; // Divide child window right by denominator
R3.top *= numerator; // Multiply child window top by numerator
R3.top /= denominator; // Divide child window top by denominator
R3.bottom *= numerator; // Multiply child window bottom by numerator
R3.bottom /= denominator; // Divide child window bottom by denominator
R3.left, // New child left
R3.top, // New child top
R3.right - R3.left, // New child width
R3.bottom - R3.top, // New child height
SWP_NOACTIVATE | SWP_NOZORDER); // Do not change order or activate
**Note you may also need to pass a scaled font (numerator/denominator) to some types of child window because you want the text bigger (you do that via WM_SETFONT).
Is that what you are trying to do???
In vino veritas
modified 22-Feb-19 16:13pm.
Last Visit: 31-Dec-99 18:00 Last Update: 23-Oct-21 23:43