Question

This code displays a window with a text label saying: "Please Enter A Number", and a button.

When you click the button it should replace the text with " TEXT ". It works, but it writes/prints the new text on top of the first text. So its overlapping.

I want the string of text to change instead of writing over the first one, but I don't know how as I'm new to windows application development.

Please help me out guys.

The whole source is:

#include <windows.h>
#include <iostream>


using namespace std;


enum { ID_LABEL = 1,ID_BUTTON0};

static  HWND static_label, button0;

HDC          hdc;
HBRUSH  NewBrush;
HINSTANCE g_hInst;


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    LPCTSTR className = TEXT("myClass");
    WNDCLASSEX wc;

    wc.cbSize        = sizeof(wc);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.cbWndExtra    = 0;
    wc.cbClsExtra    = 0;
    wc.lpfnWndProc   = WndProc;
    wc.hInstance     = hInstance;
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = TEXT("myClass");


    wc.hbrBackground  = (HBRUSH)(CreateSolidBrush(RGB(48, 38, 88)));

    wc.hIcon             = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm           = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor           = LoadCursor(NULL, IDC_ARROW);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, TEXT("ERROR! FAILED TO REGISTER CLASS!"), TEXT("FATAL ERROR!"), MB_IConerror | MB_OK);
        return 1;
    }

    HWND hwnd = CreateWindowEx(0, TEXT("myClass"), TEXT("WINDOW TITLE"), WS_OVERLAPPEDWINDOW, 450, 100, 500 + 7, 500 + 33 , NULL, NULL, hInstance, NULL);

    if(!hwnd)
    {
        MessageBox(NULL, TEXT("ERROR! FAILED TO CREATE WINDOW!"), TEXT("FATAL ERROR!"), MB_IConerror | MB_OK);

        return true;
    }  

    ShowWindow(hwnd, nShowCmd);                
    UpdateWindow(hwnd); 

    MSG msg;

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

    return (int)msg.wParam;
}



LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_PAINT:
        {

        }

        case WM_CTLCOLORSTATIC:
        {
           SetBkMode((HDC) wParam, TRANSPARENT);        

           return (LONG) GetStockObject(NULL_BRUSH);
    }

    break;

    case WM_CREATE:
    {
        static_label = CreateWindow(L"Static",L"Please Enter A Number",WS_CHILD | WS_VISIBLE,35,15,175,25,hwnd,0, g_hInst,0);

        button0 = CreateWindow(L"Button",L"OK",BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE ,80,220,35,35,hwnd,(HMENU)ID_BUTTON0,g_hInst,0);   
      }

      break;

      case WM_COMMAND: //Command from Child windows and menus are under this message

      switch(wParam) //the ID is wParam
      {
         case ID_BUTTON0: //check for our button ID
         {
             SetWindowText(static_label,L"TEXT");

             break;
         }
      }//switch. 

  break;

  case WM_DESTROY: 
         PostQuitMessage(0);
         break; // pass to DefWindowProc(...) as well

      case WM_CLOSE:
         DestroyWindow(hwnd);
         break;
   } 

    return DefWindowProc(hwnd, msg, wParam, lParam);    
}
Was it helpful?

Solution

The problem is here:

case WM_CTLCOLORSTATIC:
{
   SetBkMode((HDC) wParam, TRANSPARENT);        
   return (LONG) GetStockObject(NULL_BRUSH);
}

This code tells the static control to draw the text without a background color and not to repaint the background. So the new text is drawn on top of the old text instead of on a fresh background.

If you need some custom background to show through, then you'll have to invalidate that part of the underlying parent window and possibly use something like WS_EX_TRANSPARENT to ensure the child static control is drawn last. That way, by the time it tries to draw the new text, a fresh background should be painted.

Note that this means you cannot use WS_CLIPCHILDREN on the underlying parent window, which can increase flicker when things redraw.

OTHER TIPS

Use this code to update the label after the function SetWindowText:

SetWindowText(static_label,L"TEXT");         

ShowWindow(static_label, SW_HIDE);
ShowWindow(static_label, SW_SHOW);

Your text is being displayed in a "Static" window, and they don't expect the text to change so they don't handle it gracefully. You need to force the control to erase and redraw itself.

RedrawWindow(static_label, NULL, NULL, RDW_ERASE);

RedrawWindow(H_frame,NULL,NULL,RDW_INVALIDATE) worked for me when wanting to provoke WM_CTLCOLORSTATIC-induced changes to take immediate visible effect.

I had earlier got a partial result by SendMessage(H_frame,WM_CTLCOLORSTATIC,0,(int)SpecificControlHandle), but that only worked even in part because a called function was doing GetWindowDC and drawing stuff....

The RedrawWindow(H_frame,NULL,NULL,RDW_INVALIDATE) method is much better. I'd been changing text and background colours for text (and also the control's ID using SetWindowLong(SpecificControlHandle,GWL_ID,SomeNewID) to tell the program which route to take after WM_CTLCOLORSTATIC got sent. Making it get sent was the bit that was solved by RedrawWindow(H_frame,NULL,NULL,RDW_INVALIDATE), hence my post. If it works after changing the STATIC's ID, it ought to work after changing any other attribute or style, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top