updating/repainting controls/child-windows

I have made this big application that behaves strange. I mean, all the controls i have doesnt get painted/updated at specific moments. these moments are: when i press on maximize button, when i minimize down and when i close a modal dialogbox. (perhaps there are more than this). the thing is that these controls are child-windows. so, is there a way to update all my child windows/controls in the main app without updating every single one at specific moments but instead in one moment?. if i take one example which led me to another problem: say i have a button called made with Button button. so, i use button.Update(); button.Paint(); and then the problem is that i have to call all my controls: button and the rest (which are alot of controls) every time i want to update them. This is alot of pain. sorry I cant give you some code because its too big! And it is a wrapper class i have made. i just need to know if i should call update on every control in a window message or if there is some flag i need to set in createwindow for these controls? (i think the latter, but i dont really know) or do you have any ideas? (if what ive explained is too vague and not understandable i can make a video-capture of the app, but for now i just wait to hear from you).

some other info that is relevant:
- C++ / Win32 API (No MFC).
Last edited on
You've 'painted yourself in a corner' Rudi (that's an American 'saying'). You likely have too much code that nobody will want to wade through it all to figure what you've done wrong, but the fact of the matter is you've probably got major archetectural problems somewhere if what you are saying is happening. It should never be necessary to explicitely call routines to paint child window controls. That should happen automatically by Windows unless something is fauled up. Also, I don't know that I'd recommend wrapping things in class wrappers when you are just starting to learn this stuff, because that is going to make it considerably harder for you or anyone else to figure out what s wrong. You can try posting 2000 lines of code that only you understand, but I can't promise I'm going to wade through it. Maybe someone else will.
It should never be necessary to explicitely call routines to paint child window controls. That should happen automatically by Windows unless something is fauled up.


thanks for the reply freddie1.

i agree on that one. so what is it then? does the childs not get their parent window? isnt it just all messages being sent. i should know this, but i forget very fast. i mean, if a parent window is being updated the childs are too? maybe the childs are not created with the right parent window. ill do a check tomorrow too see if this is the case.

I have to use a wrapper because I think it makes the code smaller and simpler. I can't see myself working on a big application without a wrapper. it would've take ages to code! :P
oh well, i fixed it. or atleast it works. im not sure if its a good or a bad thing but i putted UpdateWindow(mainWindow); before return DefWindowProc(..); in the mainwindow's window procedure. atleast the child windows are being drawn. i should just use it like it is even if its not the right way too do it. :P
Here is what UpdateWindow() does...

1
2
3
4
5
6
7
8
9
10
11
UpdateWindow

The UpdateWindow function updates the client area of the specified window by sending a 
WM_PAINT message to the window if the window's update region is not empty. The function 
sends a WM_PAINT message directly to the window procedure of the specified window, bypassing
 the application queue. If the update region is empty, no message is sent. 

BOOL UpdateWindow
(
  HWND hWnd   // handle of window
); 


Well, I'm glad its working better. What I was thinking of suggesting to you is to try to eliminate piles of extra code from the app until you have perhaps just one child control left on your parent window that still evidences the problem you are having, and then post that. Hopefully only a couple hundred lines at most. Then perhaps someone (maybe even me) would be able to spot what you are doing wrong.


I have to use a wrapper because I think it makes the code smaller and simpler. I can't see myself working on a big application without a wrapper. it would've take ages to code! :P


The basic structure of your standard Sdk style Windows Api program is absolutely terrible! Generally you end up with a massive WndProc() with sometimes thousands of lines in the switch() construct. I use a function pointer setup where each Windows message gets routed to a specific message handling procedure - very much like Visual Basic code. I'm not sure if that is what you are talking about, but I just thought I'd mention it. If you want to see what I'm talking about, ask.
I use a function pointer setup where each Windows message gets routed to a specific message handling procedure


i think i know what you are talking about. and im almost sure i am doing the same thing.

i can post the two base classes i use for handling the main window and the controllers. let's see, i dont think it will be that awfull too look at:

the base wnd code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "Base.h"

namespace WindowsGUI
{
	Base::Base()
	{
	}

	Base::Base(char *classname, char *windowname, int menuid, RECT *rect, HINSTANCE hinstance)
	{
		className = classname;
		windowName = windowname;
		pRect = rect;
		hInstance = hinstance;
		
		dwStyles = WS_VISIBLE;// | WS_POPUP;
		dwExStyles = 0;
		hMenu = 0;
		menuName = MAKEINTRESOURCE(menuid);
	}

	Base::~Base()
	{
		if (g_hwndBase) DestroyWindow(g_hwndBase);
		g_hwndBase = NULL;
	}

	BOOL Base::Register()
	{
		WNDCLASSEX wc;

		wc.cbSize = sizeof(WNDCLASSEX);
		wc.style = 0;
//		wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	//used for painting the main window.
		wc.lpfnWndProc = msgRouter;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
//		wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
		wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
//		wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
		wc.lpszMenuName = menuName;
		wc.lpszClassName = className;
		wc.hInstance = hInstance;
		wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

		if(!RegisterClassEx(&wc))
		{
			MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
			return 0;
		}

		return true;
	}

	BOOL Base::Create()
	{
		//Last parameter passed is (void *)this. We are taking the this pointer (which points back at the object itself) and
		//cast it to type void *. Windows takes that pointer and passes it to the message handler for the window,
		//along with the message WM_NCCREATE, in the lParam value. This means that we can handle the WM_NCCREATE message in our
		//static message handler and quickly grab the void * that points to the WrapperClass object.
		g_hwndBase = CreateWindowEx(
			dwExStyles,
			className,
			windowName,
			dwStyles,
			pRect->left,
			pRect->top,
			pRect->right,
			pRect->bottom,
			g_hwndParent,
//			NULL,
			hMenu,
			hInstance,
			(void *)this);

		return (g_hwndBase != NULL);
	}

	BOOL Base::ShowWindow(int cmd)
	{
		::ShowWindow(g_hwndBase, cmd);
		::UpdateWindow(g_hwndBase);

		return true;
	}

	WPARAM Base::MessagePump()
	{
		MSG msg;
		while (GetMessage(&msg, NULL, 0, 0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		delete this;
		return (msg.wParam);
	}

	LRESULT CALLBACK Base::wndProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
	{
		switch(msg)
		{
			case WM_DESTROY:
				PostQuitMessage(WM_QUIT);
				break;

			default:
				return DefWindowProc(hwnd, msg, w, l);
		}
		return false;
	}

	//Default windows message handler. The message processor looks like this:
	LRESULT CALLBACK Base::msgRouter(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
	{
		Base *pWnd = 0;

		//If the window is being created, it calls SetWindowLong on the window to store the pointer to the window.
		if (msg == WM_NCCREATE) SetWindowLong(hwnd, GWL_USERDATA, (long)((LPCREATESTRUCT(l))->lpCreateParams));

		//Get the pointer to the window and calls that instance's wndproc
		pWnd = (Base *)GetWindowLongPtr(hwnd, GWL_USERDATA);

		return LRESULT (pWnd) ? pWnd->wndProc(hwnd, msg, w, l) : DefWindowProc(hwnd, msg, w, l);
	}
}


here's the window code (it inherits base).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "Window.h"

namespace WindowsGUI
{
	Window::Window(char *classname, char *windowname, int menuid, RECT *rect, HINSTANCE hinstance) : Base(classname, windowname, menuid, rect, hinstance)
	{
//		WS_CLIPCHILDREN excludes the area occupied by child windows when drawing occurs within the parent window.
//		(used for parent window only!)
//		dwStyles |= (WS_OVERLAPPEDWINDOW);
		dwStyles |= (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN);
//		dwStyles |= (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_SYSMENU);
//		dwStyles |= (WS_CLIPCHILDREN | WS_SYSMENU);
//		dwExStyles |= WS_EX_CLIENTEDGE;
		dwExStyles |= 0;
		
//		debug.Open();
		fp = fopen("window_messages.txt", "wb");
	}

	Window::~Window()
	{
//		debug.Close();
		if (g_hwndBase) DestroyWindow(g_hwndBase);
		g_hwndBase = NULL;
	}

	LRESULT CALLBACK Window::wndProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
	{
		using DemoTool::DemoTool;

		static DemoTool *ctrl;
/*
		for (int i=0; i<NUM_MESSAGES; i++)
		{
			if (msg == winMsgs[i].msgId)
			{
				//fprintf(fp, "%s\n", winMsgs[i].wmName);
				fprintf(fp, "%i : %s\n", (HWND)hwnd, winMsgs[i].wmName);
				break;
			}
		}*/

		switch(msg)
		{
			case WM_CREATE:
				try
				{
//					ctrl = new DemoTool(hwnd);
					ctrl = new DemoTool(hwnd, reinterpret_cast<CREATESTRUCT *>(l));
				}
				catch(...)
				{
					MessageBox (hwnd, TEXT("Window has been successfully created"), TEXT("Success"), MB_OK);
				}
				return 0;

			case WM_SIZE:
				ctrl->OnSize(hwnd, w, l);
				return 0;

			case WM_LBUTTONDOWN:
				ctrl->OnLButtonDown(hwnd, w, l);
				return 0;

			case WM_LBUTTONUP:
				ctrl->OnLButtonUp(hwnd, w, l);
				return 0;

			case WM_MOUSEMOVE:
				ctrl->OnMouseMove(hwnd, w, l);
				return 0;

			case WM_PAINT:
				ctrl->OnPaint(hwnd, w, l);
				return 0;

			case WM_COMMAND:
				ctrl->OnCommand(hwnd, w, l);
				return 0;

/*			case WM_NOTIFY:
				ctrl->OnNotify(hwnd, w, l);
				return 0;
*/
			case WM_DESTROY:
				PostQuitMessage(0);
				return 0;

			case WM_CLOSE:
				fclose(fp);
				delete ctrl;
				DestroyWindow(hwnd);

			default:
				UpdateWindow(g_hwndBase);	//maybe this shouldnt be here, but it works for the time being anyway.
				return DefWindowProc(hwnd, msg, w, l);
		}
		return 0;
	}

	//nID is the LOWORD of wParam and holds the resource ID of the element that was hit.
	//nCodeNotify is the HIWORD of wParam.
	bool Window::OnCommand(int nID, HWND hWndCtrl, UINT nCodeNotify)
	{
		return false;
	}

	bool Window::OnPaint()
	{
		return false;
	}
}


well about the UpdateWindow. atleast it works. so if you dont see anything wrong with this code, i think i will just continue working on the application.

thanks.
Last edited on
if you are handling the WM_PAINT message it is critically important that BeginPaint() and EndPaint() are called. It had occurred to me from your description of the problem you were having that that might be the culpret. Generally, you can get away with putting message handlers in the window procedure that don't do anything, but it won't work with WM_PAINT. In many ways that one is special.
if you are handling the WM_PAINT message it is critically important that BeginPaint() and EndPaint() are called. It had occurred to me from your description of the problem you were having that that might be the culpret. Generally, you can get away with putting message handlers in the window procedure that don't do anything, but it won't work with WM_PAINT. In many ways that one is special.


Aha! You are just right. Thanks alot mate! I should have known this myself, but thanks for saving me alot of work for later. As you say its a special one, and it really is :)
Yep! I've lost a lot of time on that one myself Rudi! Until I finally learned that lesson really good. There isn't anything that will literally bring Windows right down to its knees howling in pain like messing up the WM_PAINT message. I guess because its so critical to a graphical user interface OS.
Topic archived. No new replies allowed.