While loop on popup window not responding - c++

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;
}

Related

How can I clear TextOut?

How can I delete or hide the current textout to add new text? currently, as he adds another textout, the text overlaps the text.
I tried to use InvalidateRect(hWnd, NULL, TRUE); but I don't see any difference.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 5, 5, text.c_str(), _tcslen(_T(text.c_str())));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
Your call to TextOut is in your WM_PAINT handler. This means that the text will always be drawn on each WM_PAINT, making your call to InvalidateRect practically useless.
One way to fix this would be to have a boolean (drawText) to indicate whether you want to draw the text or not. Then in your function to clear the text:
drawText = FALSE;
InvalidateRect(hWnd, NULL, TRUE);
And in your WndProc:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
if(drawText)
TextOut(hdc, 5, 5, text.c_str(), _tcslen(_T(text.c_str())));
EndPaint(hWnd, &ps);
}
break;
In your case, the InvalidateRect call will trigger a WM_PAINT message, causing TextOut() to be called again. The answer of #mnistic is a good solution. But I think you should really put TextOut method into the real event handling (such as OnButtonClickEvent) instead of putting it into WM_PAINT.
Another technique is to re-draw the text with the background colour, something like:
HDC hdc = ::GetDC(this->m_hWnd);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, clrBackground);
TextOut(hdc, 5, 5, text.c_str(), _tcslen(_T(text.c_str())));
UpdateTextSomewhere(&text);
SetTextColor(hdc, clrText);
TextOut(hdc, 5, 5, text.c_str(), _tcslen(_T(text.c_str())));
::ReleaseDC(this->m_hWnd, hdc);
clrX are of type COLORREF. They might be set up in the form constructor orOnInitDialog e.g. clrText = RGB(0, 0, 0);.
This technique only works if the form background is a single, solid colour.

WM_PAINT and MOUSE Event. MFC/WIN32 API

i have two rectangle in my WM_PAINT and i wanted to draw Frame Rect on it once WM_MOUSE CLICK EVENT is triggered that toggle on each rectangle. is this even possible?
See #RemyLebeau's comment above regarding your mouse clicks. Then, in your WndProc, something like:
switch (uMsg)
{
// ...
case WM_PAINT:
{
PaintStruct ps;
HDC hDC = BeginPaint (hWnd, &ps);
HBRUSH hBrush = (HBRUSH) GetStockObject (LTGRAY_BRUSH); // say
if (draw_first_rectangle)
FrameRect (hDC, &my_first_rectangle, hBrush);
if (draw_second_rectangle)
FrameRect (hDC, &my_second_rectangle, hBrush);
EndPaint (hWnd, &ps);
return 0;
}
// ...
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
I'm sure you can fill in the blanks.

How to draw Text with Timer?

I used DrawText function within WM_TIMER, but it dont work. How to fix this? Thank you!
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd,23, 1000,NULL);
break;
//case WM_TIMER: ***** dont work *****
case WM_PAINT: // ***** work, but used 25% CPU *****
{
RECT rect;
HFONT hFont;
hdc = BeginPaint(hwnd, &ps);
hFont = CreateFontA(16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("Arial"));
SelectObject(hdc,hFont);
SetRect(&rect, 3, 3, 90, 50);
SetTextColor(hdc, RGB(0,0,255));
time_t rawtime;
struct tm * timeinfo;
char buffer [80];
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime (buffer,80,"%I:%M:%S %p\n%m/%d/%Y",timeinfo);
wchar_t wtext[30];
mbstowcs(wtext, buffer, strlen(buffer)+1);//Plus null
LPWSTR ptr = wtext;
DrawTextW(hdc, ptr, -1,&rect, DT_NOCLIP | DT_CENTER);
DeleteObject(hFont);
InvalidateRect(hwnd, &rect, TRUE);
UpdateWindow(hwnd);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wparam, lparam);
}
return 0;
}
Do not call InvalidateRect() or UpdateWindow() from WM_PAINT, or you will create an infinite loop of repaints.
Do not paint from the WM_TIMER. It can be done (with GetWindowDC() instead of BeginPaint() but it isn't such a good idea.
Instead put the InvalidateRect() in the WM_TIMER and leave the drawing code in WM_PAINT. You can optimize, as #typ1232 said in the comments, by creating the font only once, but that's not strictly necessary.
The UpdateWindow() call should not generally be necessary, unless you are in a tight CPU loop and need to show the window just now: if the invalidation is done in a timer and the timeout is not too short you won't need it. But if your timeout is very short you can force the redraw calling UpdateWindow() just after InvalidateRect().
Your WM_TIMER code should prepare the string to be drawn, save it and then call InvalidateRect. The WM_TIMER code can not draw directly, and one reason is that BeginPaint will not work properly during a WM_TIMER message. BeginPaint is only defined during a WM_PAINT message. So WM_TIMER can prepare the data to be drawn, but then use InvalidateRect to request that a WM_PAINT be generated.
You must also remove the InvalidateRect and UpdateWindow calls from the WM_PAINT code. They will cause an infinite loop of painting.

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;
}

c++ win32 output a text

im using visual studio c++ 2008 i created project that contents the full window code. i don't know how to output text to window. i mean i have full functional window with menu bar and under the menu bar there is the body im trying to ouput the text in the body but how?
This page has a sample on how to do it in Win32:
http://www.rohitab.com/discuss/index.php?showtopic=11454
The code below is the Window Procedure for the window, if you note the WM_PAINT (That is the message that tells the window to paint itself) the code is simply drawing the text to the Device Context, which is the client area of the window.
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
LPSTR szMessage = "darkblue 0wNz j00!";
switch(Message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 70, 50, szMessage, strlen(szMessage));
EndPaint(hwnd, &ps);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
As an out of topic note, I suggest you to try some 3rd party library instead, as it can be much more convenient. Take a look at wxWidgets for instance.