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.
Related
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;
}
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.
I am trying to trigger a WM_PAINT message form WM_TIMER; the timer works, but RedrawWindow() function does not seem to do anything. What am I doing wrong?
Here is my Callback function:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
PAINTSTRUCT Ps;
COLORREF clrBlue = RGB(25, 55, 200);
RECT Recto = { 20, 28, 188, 128 };
COLORREF clrAqua = RGB(128, 255, 255);
COLORREF clrRed = RGB(255, 25, 5);
static bool x = true;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_TIMER:
//InvalidateRect(hWnd ,NULL , FALSE);
//RedrawWindow(hWnd , NULL , NULL , RDW_INVALIDATE);
RedrawWindow(hWnd,NULL,NULL,RDW_INTERNALPAINT);
break;
case WM_PAINT:
if(x)
{
hdc = BeginPaint(hWnd, &ps);
SetTextColor(hdc, clrRed);
TextOut(hdc, 50, 42, L"Some text", 13);
EndPaint(hWnd, &ps);
toggle(x);
}
else
{
hdc = BeginPaint(hWnd, &ps);
SetTextColor(hdc, clrRed);
TextOut(hdc, 50, 42, L"Another text", 13);
EndPaint(hWnd, &ps);
toggle(x);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
As x is defined as a local variable in your function, it always gets the value true when the function is called. That is, the code in WM_PAINT never gets to the else branch of the if.
Try, for example, changing the definition of x to static bool x = true; to get the toggling work.
Additionally, you need to invalidate the window's contents to get it redrawn:
RedrawWindow(hWnd,NULL,NULL,RDW_INVALIDATE | RDW_INTERNALPAINT);
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;
...
}
...
}
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.