How do I create a window that constantly updates?

I have been trying to learn how to create a window in a program, but every time
I try some code, the screen only updates when I move my mouse. Why does this happen
and how can I fix it? How do I make a window that updates even when I don't move the mouse?
I've been searching for a solution all day.

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
#include <iostream>
#include <windows.h>

using namespace std;

int i = 0;

LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam);

int WINAPI WinMain(HINSTANCE currentInstance, HINSTANCE previousInstance, PSTR cmdLine, INT cmdCount) {
	const char *CLASS_NAME = "myWin32WindowClass";
	WNDCLASS wc{};
	wc.hInstance = currentInstance;
	wc.lpszClassName = CLASS_NAME;
	wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
	wc.lpfnWndProc = WindowProcessMessages;
	RegisterClass(&wc);

	CreateWindow(CLASS_NAME, "Test Window",
		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT,
		704, 480,
		nullptr, nullptr, nullptr, nullptr);

	MSG msg{};
	while (GetMessage(&msg, nullptr, 0, 0)) {

		TranslateMessage(&msg);
		DispatchMessage(&msg);

                i++;
                cout << i << " ";
	}

	return 0;
}

LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) {
	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hwnd, msg, param, lparam);
	}
}
Last edited on
Use a timer:
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
#include <windows.h>
#include <strsafe.h>
#include <ctime>
#include <tchar.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nWinMode)
{
   const TCHAR szWinName[] = TEXT("WinClock");
   WNDCLASSEX  wc;

   wc.cbSize        = sizeof(WNDCLASSEX);
   wc.hInstance     = hInstance;
   wc.lpszClassName = szWinName;
   wc.lpfnWndProc   = WndProc;
   wc.style         = 0;
   wc.hIcon         = (HICON) LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
   wc.hIconSm       = (HICON) LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
   wc.hCursor       = (HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
   wc.lpszMenuName  = NULL;
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 0;
   wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

   if (RegisterClassEx(&wc) == 0)
   {
      MessageBox(NULL, TEXT("Couldn't Register the Window Class!"), TEXT("ERROR"), MB_OK | MB_ICONERROR);
      return E_FAIL;
   }

   const TCHAR szAppTitle[] = TEXT("Win Clock");

   HWND hwnd = CreateWindow(szWinName, szAppTitle,
                            WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
                            0, 0,
                            210, 60,
                            HWND_DESKTOP, NULL, hInstance, NULL);

   if (hwnd == NULL)
   {
      MessageBox(NULL, TEXT("Couldn't Create the Main Window!"), TEXT("ERROR"), MB_OK | MB_ICONERROR);
      return E_FAIL;
   }

   // start a timer; interrupt once per second
   SetTimer(hwnd, 1, 1000, NULL);

   ShowWindow(hwnd, nWinMode);
   UpdateWindow(hwnd);

   MSG msg;

   while (GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   // stop the timer
   KillTimer(hwnd, 1);

   return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   const size_t  strSize      = 255;
   static TCHAR  str[strSize] = TEXT("");
   static size_t strLen       = 0;

   switch (message)
   {
   case WM_CREATE:
   case WM_TIMER:
      // timer went off, get the new time
      struct tm newtime;
      time_t    t;

      t = time(NULL);

      localtime_s(&newtime, &t);

      // format the new time to a string
      _tasctime_s(str, strSize, &newtime);

      // remove formatting
      StringCchLength(str, (int) strSize, &strLen);

      str[strLen - 1] = TEXT('\0');

      // display the new time
      InvalidateRect(hwnd, NULL, FALSE);
      return S_OK;

   case WM_PAINT:
      HDC         hdc;
      PAINTSTRUCT ps;

      hdc = BeginPaint(hwnd, &ps);

      StringCchLength(str, (int) strSize, &strLen);
      TextOut(hdc, 4, 1, str, (int) strLen);

      EndPaint(hwnd, &ps);
      return S_OK;

   case WM_DESTROY:
      PostQuitMessage(0);
      return S_OK;
   }

   return DefWindowProc(hwnd, message, wParam, lParam);
}

Be careful about setting too small a timer interval, it can hog the system unnecessarily.
This is obviously a Windows question.
If you need your message loop to spin even when there are no messages you need to use PeekMessage. GetMessage blocks until there is a message, such as a mouse movement.
I got an error from the code:

||=== Build: Debug in Test (compiler: GNU GCC Compiler) ===|
obj\Debug\main.o||In function `WndProc(HWND__*, unsigned int, unsigned long long, long long)':|
C:\Downloads\Projects\C++\Test\Test\main.cpp|103|undefined reference to `__imp_TextOutA'|
||error: ld returned 1 exit status|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|
I dunno if it still works or is a 'valid approach' but for a long time you could have a sort of feedback loop where it invalidated its own rectangle in onpaint which had it draw, but the drawing told it it needed to be drawn again, so it would draw, which would tell it to draw again... :)
it worked for very simple graphics or updated data edit boxes but falls apart if you have anything too complex.
This avoided needing a timer in smaller, simpler examples, but I think it may be kind of a hackity approach.
Last edited on
Try adding Gdi32.lib to your libraries.
When I added that to my library I got an error:
||=== Build: Debug in Test (compiler: GNU GCC Compiler) ===|
ld.exe||cannot find -lGdi32.lib|
||error: ld returned 1 exit status|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
Topic archived. No new replies allowed.