Win32 DrawText Colour and Display - c++

I'm trying to display some text on my window. I'm using Win32/OpenGL with c++.
I found this question which is the method I'm trying to implement, unfortunately, I'm doing something wrong as it's not working.
This is my CALLBACK function:
LRESULT CALLBACK WinProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam){
LONG lRet = 0;
PAINTSTRUCT ps;
switch (uMsg)
{
case WM_SIZE:
if(!g_bFullScreen)
{
SizeOpenGLScreen(LOWORD(lParam),HIWORD(lParam));
GetClientRect(hWnd, &g_rRect);
}
break;
case WM_PAINT:
//BeginPaint(hWnd, &ps);
//adding code from SO question here
HDC hdc = BeginPaint(hWnd, &ps); //line 403
RECT rec;
// SetRect(rect, x ,y ,width, height)
SetTextColor(hdc, RGB(255,255,255))
SetRect(&rec,10,10,100,100);
// DrawText(HDC, text, text length, drawing area, parameters "DT_XXX")
DrawText(hdc, TEXT("Text Out String"),strlen("Text Out String"), &rec, DT_TOP|DT_LEFT);
EndPaint(hWnd, &ps);
ReleaseDC(hWnd, hdc);
//EndPaint(hWnd, &ps);
break;
case WM_KEYDOWN: //line 418
//some key presses
case WM_CLOSE:
PostQuitMessage(0);
break;
default://line 510
lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
return lRet;
}
I seem to be implementing something wrong or overlooking something because I just can't see it.
It errors with this: \main.cpp(403) : see declaration of 'hdc'
If someone could suggest an edit or help me with where I'm going wrong, that would be great. Thanks in advance.
update
There's are the errors (added lines to code above):
main.cpp(418): error C2360: initialization of 'hdc' is skipped by 'case' label
main.cpp(506): error C2360: initialization of 'hdc' is skipped by 'case' label
main.cpp(510): error C2361: initialization of 'hdc' is skipped by 'default' label

You can't declare a variable in the middle of a switch statement. It must either be inside a block, or declared before the beginning of the switch.
Just put the code inside the case in brackets {} and the error will go away.

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

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.

C++ Windows Minimize Not Registered

I have added minimize & restore cases to my even processing, but I found out they are never hit.
Only on startup of the program does Size_Minimized get hit. Afterwards, minimize case never happens.
The Size_Restore case never happens either.
Debug stopping at Size_Minimize only on startup of program:
My other cases work, so I have no idea why minimize & restore dont trigger my code or break points.
I conclude that Size_Minimized & Size_Restore are not related to what I need.
What is it I need to know to handle minimize/restore?
Code, in case I did it wrong:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
PAINTSTRUCT ps;
HDC hdc;
switch(message){
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case SIZE_MINIMIZED:
break;
case SIZE_RESTORED:
break;
case WM_SIZING:
case WM_SIZE:
if(engine.isReady()) engine.resizeDevice();
if(engine.isReady()) engine.draw();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
SIZE_MINIMIZED and SIZE_RESTORED are constants passed to you through the WM_SIZE message; they are not window messages. Your breakpoint is getting hit whenever your window receives a window message with the same id as SIZE_MINIMIZED and/or SIZE_RESTORED.
You would need to have your code look something like this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
PAINTSTRUCT ps;
HDC hdc;
switch(message){
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
switch(wParam) {
case SIZE_MINIMIZED:
// Do whatever
break;
case SIZE_RESTORED:
// Do whatever
break;
}
case WM_SIZING:
if(engine.isReady()) engine.resizeDevice();
if(engine.isReady()) engine.draw();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

use InvalideRect() to change a GDI shape

I asked my question yesterday but could not get a correct answer. now ill ask it more clearly.
using win api I created a window and a button. infront of the button there is a circle drawn in green color. once the button is pressed the circle should turn to red color.
(I'm using C++, and mingw compiler.)
here is my code
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
HBRUSH brusha;
brusha=CreateSolidBrush(RGB(0,255,0));
switch(msg)
{
case WM_CREATE:
{
b=CreateWindowEx(WS_EX_CLIENTEDGE,
"BUTTON",
"red",
WS_CHILD|WS_VISIBLE|
BS_DEFPUSHBUTTON,
350,
100,
100,
40,
hWnd,
(HMENU)BUTTON,
GetModuleHandle(NULL),
NULL);
}
break;
case WM_PAINT:
{
hDC=BeginPaint(hWnd,&ps);
SelectObject(hDC,brusha);
Ellipse(hDC, 20, 20, 100, 100);
EndPaint(hWnd, &ps);
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case BUTTON:
{
brusha=CreatSolideBrush(RGB(255,0,0));
InvalidateRect( hWnd,0,false);
}
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
this compiles without errors. but nothing happens on button click
Well the problem is that you you always draw with a green brush. Look at your code
HBRUSH brusha;
brusha=CreateSolidBrush(RGB(0,255,0));
switch(msg)
{
...
case WM_PAINT:
{
hDC=BeginPaint(hWnd,&ps);
SelectObject(hDC,brusha);
...
In this code brusha is always going to be a green brush when you go into WM_PAINT.
You seem to think that just because you assign a red brush to the brusha variable in the WM_COMMAND part that somehow that is going to be remembered for the next paint, but that's not true. Remember that in C++ variables are created afresh each time you enter a function, and destroyed each time you exit a function. So the way you have written the code cannot work.
Probably the simplest way is to make the hbrusha variable static. Static variables are not created and destroyed each time you enter and exit a funciton. Something like this
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
static HBRUSH brusha;
switch(msg)
{
case WM_CREATE:
brusha=CreateSolidBrush(RGB(0,255,0)); // set the brush green on create
...
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case BUTTON:
brusha=CreatSolideBrush(RGB(255,0,0));
InvalidateRect( hWnd,0,false);
}
break;
...
}
...
}

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.