Break timer win32 c++ - c++

I am trying to create an animation loop through the use of timers. I want to call a different SetRenderParams(int) after approximately 5-10 seconds. I don't know how timers work and the documentation I can find online is VERY minimal.
I tried if and while statements to break the timer, but I have come to understand it does not work as a loop, so it cannot check counts. I am never able to move to IDT_TIMER2. I am thinking I might not need multiple timers, since I do not mind keeping the same animation speed (which is what the timer essentially accomplices), but a way to alternate SetRenderParams(int) without breaking from the timer, maybe(?).
I checked timerqueues as well, but while I was checking them I got more and more confused... The link I followed to come this far was the following, however this one does not show a way to input multiple animations in sequence, only one. To be clear, I do not want to have multiple animations at the same time. I want animation after animation, distinct from each other. http://www.winprog.org/tutorial/animation.html
The code I posted is clear from all the experiments I tried.
LRESULT Framework::MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// Set two timers.
const int IDT_TIMER1 = 1;
const int IDT_TIMER2 = 2;
SetTimer(hWnd, // handle to main window
IDT_TIMER1, // timer identifier
50, // 10-second interval
NULL); // no timer callback
SetTimer(hWnd, // handle to main window
IDT_TIMER2, // timer identifier
20000, // five-minute interval
NULL); // no timer callback
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
//=== Add code for Rendering Models);
RenderScene(hdc);
EndPaint(hWnd, &ps);
}
break;
case WM_TIMER:
{
int count = 0;
RECT rcClient;
GetClientRect(hWnd, &rcClient);
switch (wParam)
{
case IDT_TIMER1:
SetRenderParams(13);
InvalidateRect(hWnd, NULL, TRUE);
ReleaseDC(hWnd, hdc);
break;
case IDT_TIMER2:
SetRenderParams(14);
InvalidateRect(hWnd, NULL, TRUE);
ReleaseDC(hWnd, hdc);
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
edit: forgot to add the initialized variables.
edit: providing a link to the .sln file https://www.mediafire.com/file/x42hy751n89z5bf/Rasteriser.zip/file

I came up with a "solution" but it is really grindy code. I create an Update method with clocks in it and then I call in inside the WM_TIMER . I have to manually input all the clock commands and since I have around 20 SetRenderParams, we are talking about very unoptimized program. Here is the code:
void Framework::UpdateCube(HWND hWnd)
{
clock_t t;
t = clock();
if (t < 10000.0f)
{
SetRenderParams(13);
InvalidateRect(hWnd, NULL, TRUE);
t = clock();
}
if (t >= 10000.0f && t < 10100.0f)
{
SetRenderParams(10);
InvalidateRect(hWnd, NULL, TRUE);
}
if (t >= 10100.0f && t < 20100.0f)
{
SetRenderParams(15);
InvalidateRect(hWnd, NULL, TRUE);
}
if (t >= 20100.0f && t < 20200.0f)
{
SetRenderParams(10);
InvalidateRect(hWnd, NULL, TRUE);
}
}
.
.
.
case WM_TIMER:
{
RECT rcClient;
GetClientRect(hWnd, &rcClient);
UpdateCube(hWnd);
}
break;

Related

While loop on popup window not responding

I've a popup window that displays a picture. Each time it displays a picture, the content is changed by another code to make it look like a motion picture.
Without using a while loop, it just displays the picture and the window doesn't hang, it responds perfectly well.
But I'm unable to achieve what I want without a while loop. when I use the while loop to create the motion picture. It works, but after a while the window stops responding.
Here's an example of the window procedure:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
HDC hdc;
PAINTSTRUCT ps;
switch(msg){
case WM_PAINT:{
hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics graph(hdc);
while(true){
Sleep(100);
Image img(L"Test.png");
graph.DrawImage(&img, 0, 0, 1000, 700);
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
As #RetiredNinja said in comments, this code really needs a timer, not a while loop. If you block the window procedure, the window will stop responding to messages. You must return flow to the thread's message loop after each message is processed.
At startup, load your initial image, start the timer, and invalidate the window. Done.
Whenever the timer fires, update the image as needed and invalidate the window to trigger a repaint. Done.
Every time the window procedure receives a WM_PAINT message, draw the current image as-is onto the window. Done.
That is all you need to do. No threads are needed. And the app remains responsive at all times, because no single message is blocked for more than a few milliseconds.
Try something more like this instead:
Image *img = nullptr;
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){
switch(msg){
case WM_CREATE:
img = Image::fromFile(L"Test.png", FALSE);
SetTimer(hWnd, 1, 100, NULL);
break;
case WM_DESTROY:
KillTimer(hWnd, 1);
delete img;
PostQuitMessage(0);
break;
case WM_TIMER:{
// update img as needed...
InvalidateRect(hWnd, NULL, TRUE);
break;
}
case WM_PAINT:{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics graph(hdc);
graph.DrawImage(img, 0, 0, 1000, 700);
EndPaint(hWnd, &ps);
break;
}
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}

C++ updating windows window from async thread

So I just started with C++ and wanted to create a window with a button that starts an asynchronous thread for a counter that counts from 5 to 0, representing a long time consuming task. The number should've been shown on the Window and get updated every second while the counter is counting. For that the child thread has to communicate in any way with the Message Loop of the main window thread.
I tried to do this by:
Sending an UpdateWindow with the windowhandle of the main window
Sending an PostMessage with the windowhandle of the main window
But in both cases, the window does not get updatet. So I'm suspecting an error by either sending the window handle from the main thread to the child thread or sending the UpdateWindow message from the child thread to the main thread or both or I'm completely off track and everythig is wrong.
Maybe my way of thinking is also wrong and i should do that on another way, still, i don t know how i even should start.
#include "stdafx.h"
#include "Testproject.h"
#include <iostream>
#include <string>
#include <thread>
#define MAX_LOADSTRING 100
// Global variables:
HINSTANCE hInst; // Aktuelle Instanz
WCHAR szTitle[MAX_LOADSTRING]; // Titelleistentext
WCHAR szWindowClass[MAX_LOADSTRING];
HWND Button1;
int i = 0;
My Counter:
void counterr(HWND hWnd)
{
i = 5;
while(i>0)
{
i -= 1;
//UpdateWindow(hWnd);
PostMessage(hWnd, WM_PRINT, NULL, NULL);
Sleep(1000);
}
}
standard window and message loop things from VisualStudio2017
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
Button1 = CreateWindow(L"Button",L"Counter",WS_VISIBLE|WS_CHILD|WS_BORDER,0,40,100,20,hWnd,(HMENU) 1,nullptr,nullptr);
break;
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Menüauswahl bearbeiten:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case 1:
{
std::thread t1(counterr, hWnd);
t1.detach();
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PRINT:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
//TODO: Zeichencode, der hdc verwendet, hier einfügen...
RECT rc;
RECT rc2 = { 0, 0, 0, 0 };
int spacer = 3;
GetClientRect(hWnd, &rc);
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0, 0, 0));
std::wstring strOut = std::to_wstring(i); // or wstring if you have unicode set
DrawText(hdc, strOut.c_str(), strOut.length(), &rc, DT_SINGLELINE);
DrawText(hdc, strOut.c_str(), strOut.length(), &rc2, DT_CALCRECT);
rc.left = rc.left + rc2.right + spacer;
std::wstring strOut2 = L"heya";
DrawText(hdc, strOut2.c_str(), strOut2.length(), &rc, DT_TOP | DT_LEFT | DT_SINGLELINE);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
standard stuff again and end of Code
The usual way to do this, is to either call SendMessage() or PostMessage() with a custom message ID to notify the UI about some changes made by the thread.
Updating the UI directly from the thread is bad practice, because the thread should only do "work" and not be concerned about how the results of this work will be presented by the UI.
You already were on the right track by using PostMessage. But instead of using WM_PRINT you should define a custom message ID like this:
const UINT WM_APP_MY_THREAD_UPDATE = WM_APP + 0;
Messages in the range WM_APP through 0xBFFF are reserved for private use by the application, so you don't have to worry that some Windows component already uses your message ID.
Your thread function then calls:
PostMessage(hWnd, WM_APP_MY_THREAD_UPDATE, 0, 0);
In your WndProc replace the case WM_PRINT: by:
case WM_APP_MY_THREAD_UPDATE:
// Tell Windows that the window content is no longer valid and
// it should update it as soon as possible.
// If you want to improve performance a little bit, pass a rectangle
// to InvalidateRect() that defines where the number is painted.
InvalidateRect( hWnd, nullptr, TRUE );
break;
There is another issue with your code:
Your counterr thread function updates the global variable i without taking synchronization into account. The GUI thread who outputs the variable in WM_PAINT may not "see" that the variable has been changed by the other thread and still output the old value. For instance, it may have stored the variable in a register and still uses the register value instead of rereading the actual value from memory. Matters become worse when threads run on multiple CPU cores, where each thread has its own cache.
It may work all the time on your own machine but always or sometimes fail on users machines!
Synchronization is a very complex topic so I suggest looking up "C++ thread synchronization" using your favorite search engine and be prepared for some lengthy reading. ;-)
A simple solution for your code would be to add a local variable i to the thread function and only operate on this local variable from within the thread (a good idea anyway). When you post the WM_APP_MY_THREAD_UPDATE message, you would pass the local i as the argument for the WPARAM or LPARAM of the message.
void counterr(HWND hWnd)
{
int i = 5; // <-- create local variable i instead of accessing global
// to avoid thread synchronization issues
while(i>0)
{
i -= 1;
// Pass local variable with the message
PostMessage(hWnd, WM_APP_MY_THREAD_UPDATE, static_cast<WPARAM>( i ), 0);
Sleep(1000);
}
}
To avoid confusion i would add a prefix to the global i:
int g_i = 0;
Then in the case branch for WM_APP_MY_THREAD_UPDATE you would update g_i from the WPARAM parameter:
case WM_APP_MY_THREAD_UPDATE:
g_i = static_cast<int>( wParam );
InvalidateRect( hWnd, nullptr, TRUE );
break;
Of course you would also use g_i during WM_PAINT:
case WM_PAINT:
// other code here....
std::wstring strOut = std::to_wstring(g_i);
// other code here....
break;

Client Area Flickers when Drawing a Line

The problem I am having is that when I draw my line, the screen flickers every time it redraws. I just can't quite figure out how to not make it flicker. I understand the flicker is coming from me redrawing the client area hundreds of times a second as I move my mouse with my left button down but how would I be able to get around this?
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HDC hdc;
PAINTSTRUCT ps;
RECT rect;
RECT size;
static POINT point1;
static POINT point2;
static HBRUSH origBrush;
static bool drawingLine = false;
switch (message)
{
case WM_CREATE:
origBrush = CreateSolidBrush(RGB(0, 0 , 0) );
break;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rect);
GetWindowRect(hwnd, &size);
Rectangle(hdc, 10, 10, 80, 80 );
if(drawingLine == true)
{
MoveToEx(hdc, point1.x, point1.y, NULL);
LineTo(hdc, point2.x, point2.y);
}
EndPaint (hwnd, &ps);
return 0;
//Has all the commands that exist in your program.
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_COLOR_RED:
break;
case ID_COLOR_BLUE:
break;
case ID_COLOR_BLACK:
break;
case ID_THICKNESS_1:
break;
case ID_THICKNESS_2:
break;
case ID_THICKNESS_3:
break;
}
break;
case WM_LBUTTONDOWN:
drawingLine = true;
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
point1.x = LOWORD(lParam);
point1.y = HIWORD(lParam);
MoveToEx(hdc, point1.x, point1.y, NULL);
break;
case WM_MOUSEMOVE:
point2.x = LOWORD(lParam);
point2.y = HIWORD(lParam);
InvalidateRect(hwnd, NULL, 1);
break;
case WM_LBUTTONUP:
point2.x = LOWORD(lParam);
point2.y = HIWORD(lParam);
drawingLine = false;
break;
//Causes the program to exit.
case WM_DESTROY:
PostQuitMessage(0);
break;
}
The main thing to do is respond to WM_ERASEBKGND and return true to prevent the default re-drawing of the background.
Then you'll need to erase the old line you before drawing the new one. Just for example, you might save bits from under the line, draw it, then restore those (and only those) pixels before drawing the line, so when you need to erase it, you can just restore those pixels to erase it.
The obvious alternative (that's usually simpler though theoretically at least a little slower) is to use double buffering. Do roughly the drawing you are now, but to an off-screen bitmap. Then, when it's all complete just BitBlt from there to the screen.

WINAPI your own keyboard onPress and onReleased

Currently, I am creating my own function onPress and onRelease. However, I am having problem with my onRelease function. Apparently, my onRelease kept on triggering even if I have not release my keyboard.
I suspected it has to do with the number of cycle inside the CPU but I wasn't sure of this theory. Somehow, maybe the cycle is slower than my frame, that why the PeerMessage return false? As no event was triggered.
Solution to it:
**Under the WinProc function create a new case called WM_KEYUP. This event will trigger once the user leave the button. It help to solve the number of cycle inside the CPU issued.
**
*Note:
I have update my detail of my code.
Description. Window Programming
I have two std::array that store my keyboard data
1) InputCurr
2) InputPrev
std::array<char, 256> inputPrev;
std::array<char, 256> inputCurr;
While(TRUE) {
std::copy(InputCurr.begin(), InputCurr.end(), InputPrev.begin());
inputCurr.fill(0);
while(PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&uMsg);
DispatchMessage (&uMsg);
}
if(onReleased(x030)) //Button 0
//do something
}
char onReleased(char key)
{
return (inputCurr[key] && !inputPrev[key])? 1 : 0;
}
void VEInputMessage(WPARAM key)
{
inputCurr[key]= 1; //Set to true of the keyboard key
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC dc; /* device context */
PAINTSTRUCT ps; /* the paint struct */
RECT rect;
UNREFERENCED_PARAMETER(rect);
switch (msg)
{
/* when the window is created */
case WM_CREATE:
break;
/* when the rectangle is drawn */
case WM_LBUTTONDOWN:
break;
case WM_MOUSEMOVE:
break;
case WM_PAINT:
dc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
/* When it's time for the window to be closed and removed */
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
VEINPUT::VEInputMessage(wParam); //Updated the input key
if(wParam == AEVK_ESCAPE)
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}

PeekMessage not getting the message?

I've created a custom message type for use in resizing my Window, called WM_NEED_RESIZE. I've defined it in my .h file, and initialized in my .cpp file. I have also registered my WindowProc function to accept messages. Here is the code for these items:
const uint32 WindowsGLWindow::WM_NEED_RESIZE = WM_USER + 100;
LONG WINAPI WindowsGLWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;// do I need this?
static sint32 newWidth = 0;
static sint32 newHeight = 0;
bool res = false;
switch (uMsg) {
case WM_PAINT:
//display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SIZE:
//glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
res = PostMessage(hWnd, WindowsGLWindow::WM_NEED_RESIZE, wParam, lParam);
std::cout << "WM_SIZE: " << res << std::endl;
return 0;
case WindowsGLWindow::WM_NEED_RESIZE:
std::cout << "WindowsGLWindow::WM_NEED_RESIZE" << std::endl;
break;
case WM_CHAR:
switch (wParam) {
case 27: /* ESC key */
PostQuitMessage(0);
break;
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
In another function I am running through PeekMessage(..) to collect all messages. Here is the snippet of the message pump:
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) == TRUE) // maybe use GetInputState(?) as well?
{
if (msg.message == WM_QUIT)
retVal = -1;
if (msg.message == WindowsGLWindow::WM_NEED_RESIZE) {
uint32 newWidth = LOWORD(msg.lParam);
uint32 newHeight = HIWORD(msg.lParam);
std::cout << "PeekMessage: WindowsGLWindow::WM_NEED_RESIZE" << std::endl;
// call resize only if our window-size changed
if ((newWidth != width_) || (newHeight != height_)) {
resize(newWidth, newHeight);
}
PostMessage(msg.hwnd, WM_PAINT, 0, 0);
}
switch (msg.message) {
case WM_MOUSEMOVE:
// Retrieve mouse screen position
//int x = (short) LOWORD(lParam);
//int y = (short) HIWORD(lParam);
// Check to see if the left button is held down:
//bool leftButtonDown = wParam & MK_LBUTTON;
// Check if right button down:
//bool rightButtonDown = wParam & MK_RBUTTON;
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_KEYUP:
case WM_KEYDOWN:
/*
switch (msg.wParam) {
case 'W':
// w key pressed
break;
case VK_RIGHT:
// Right arrow pressed
break;
default:
break;
}
*/
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
My problem is that the WM_NEED_RESIZE message is only found once in the message queue when the window first opens, after which it is never found in the message queue by my PeekMessage(..). I'm really not sure why this is happening. It is, however, being received by the WindowProc(..) method (which doesn't really help me). I would appreciate any help you guys could provide.
Thanks
Jarrett
Dont use std::cout expecting to see that output in your debugger, insted use OutputDebugString(); .
You need to pass your class pointer to the last parameter of your call to CreateWindowEx, then retrieve that pointer from the LPCREATESTRUCT passed to you in the LPARAM of WM_CREATE, your class pointer will be in the lpCreateParmas feild of the struct. Set your clas pointer to the GWLP_USERDATA of your window, and on any other message calls , call GetWindowsLong , retrieve your class pointer, then pass the message, wparam, and lparam all off to your internal class message handler.
http://msdn.microsoft.com/en-us/library/ff381400%28v=VS.85%29.aspx
The message pump loop that you are showing will exit as soon as the queue is empty. I can't tell from what you've posted if it ever gets entered again.
If this is your main message pump, you should use GetMessage() instead, as it will wait until something is available before returning. Take a look at this MSDN article for more info.