5

Solution: As said below, it is probably better to create your own method for the text, instead of trying to get the control to behave abnormally. So, creating a custom control for this would be best. I found a tutorial that explains it all: http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics .

This has been asked, no practical solutions though.

I am trying to use static controls to show text so updating is as easy as just sending a message. I can just as easily scratch the controls and just use plain DrawText() but it seems like a "sloppier" solution.

this is the owner draw method.

else if (message == WM_DRAWITEM) {  
    LPDRAWITEMSTRUCT pDIS;
    pDIS = (LPDRAWITEMSTRUCT)lParam;
    RECT rc;

    SetTextColor(pDIS->hDC, RGB(200,10,60));
    SelectObject(pDIS->hDC, (HPEN)GetStockObject(NULL_PEN));
    SelectObject(pDIS->hDC, (HBRUSH)GetStockObject(NULL_BRUSH));
    SetBkMode(pDIS->hDC, TRANSPARENT);
    // Start Drawing
    Rectangle(pDIS->hDC, 0, 0, pDIS->rcItem.right+1, pDIS->rcItem.bottom+1);
    DrawText(pDIS->hDC, "teststring", 10, &pDIS->rcItem, 0); 

    return 0;
}

and I get: static_controls

Left is what I get, right is what I want.

CreateWindow("STATIC", "teststring", WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, 20, 20, 120, 40, hwnd, (HMENU)(IDC_STATIC_TEST), GetModuleHandle(NULL), NULL);   

That is what I use to create the static.

I have spent well over 4 hours on and off trying to do this, I have tried everything.

Any help is appreciated.

Would it be better to just forget the static controls and fall back on just using DrawText().

Thanks.

// create window
hwnd = CreateWindowEx (0, szClassName, "Test Transparent Static Main Window", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX , 100, 100, 300, 200, HWND_DESKTOP, NULL, hThisInstance, NULL);         
ShowWindow (hwnd, nFunsterStil);
// set globals
hWnd = hwnd;
hInstance = hThisInstance;

// main window message loop
while (GetMessage (&messages, NULL, 0, 0)) {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
}
return messages.wParam;
}






// Main Window Procedure
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
// local variables
PAINTSTRUCT ps;
HDC hdc;    


switch (message) {

    case WM_CREATE:   
        {     
        LRESULT lRes = DefWindowProc(hwnd, message, wParam, lParam);
        HWND hWndStatic = CreateWindowEx(0, "Static", NULL, WS_CHILD | WS_VISIBLE, 10, 10, 200, 100, hwnd, NULL, hInstance, NULL);
        StaticWndProc = (WNDPROC)SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)MyStaticWndProc);
        return lRes;            
        }
        break;

    case WM_PAINT: 
        hdc = BeginPaint(hwnd, &ps); 
        SetBkMode(hdc, TRANSPARENT);
        SetBkColor(hdc, RGB(110,110,110));
        EndPaint(hwnd, &ps);
        break;

   case WM_DESTROY:
        PostQuitMessage(0);       
        break;

    default:  
        return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}







LRESULT CALLBACK MyStaticWndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)     {   

if (Message == WM_PAINT) {   
    RECT rc;
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    GetClientRect(hwnd, &rc);
    SetBkMode(hdc, TRANSPARENT);
    SetTextColor(hdc, RGB(0,100,200));
    DrawText(hdc, "TESTTEXT", 8, &rc, DT_CENTER | DT_VCENTER | SS_LEFT);

    EndPaint(hwnd, &ps);

    return 0;
}

return StaticWndProc(hwnd, Message, wparam, lparam);
}

---------EDIT---------------------------------------------------------

Example 2

Evan Carslake
  • 2,267
  • 15
  • 38
  • 56
  • 3
    Just register your own window class and draw the text yourself. Trying to shoehorn non-default behaviour into the system classes is often an exercise in frustration, and in this particular case it would be trivial to simply roll your own. – Jonathan Potter May 03 '14 at 08:30
  • WS_CLIPCHILDREN screws it up because it prevents the parent window from drawing in the areas occupied by child controls. That's counter-productive to your goal: to get the parent control to draw its background underneath a transparent child control. – Cody Gray - on strike May 07 '14 at 06:41
  • I would agree with @CodyGray, the alternative (each child would need access to, and draw part of the main window background picture) is fiddly, especially when you resize the main window and/or move the child controls – Edward Clements May 07 '14 at 07:44

1 Answers1

4

No need to do Owner Draw, you can just use SetWindowText() and handle the WM_CTLCOLORSTATIC message, see the code in this SO Answer <-- this will not work if the window has a pattern background, we need to subclass the static control and use the transparent background mode while drawing the text:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{   MSG msg;
    WNDCLASS w;

    hInst = hInstance;
    memset(&w,0,sizeof(WNDCLASS));
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc;
    w.hInstance = hInst;
    w.hbrBackground = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 0, 0));
    w.lpszClassName = L"My Class";
    w.hCursor = LoadCursor(NULL, IDC_ARROW); 
    RegisterClass(&w);

    HWND hWndWindow = CreateWindow(L"My Class", L"My title", WS_OVERLAPPEDWINDOW, 300, 200, 800, 600, NULL, NULL, hInst, NULL);

    ShowWindow(hWndWindow, nCmdShow);
    UpdateWindow(hWndWindow);

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

    DeleteObject(w.hbrBackground);

    return msg.wParam;
}

WNDPROC StaticWndProc = NULL;
TCHAR szText[] = _T("TestString");

LRESULT CALLBACK MyStaticWndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{   if (Message == WM_PAINT)
    {   RECT rc;
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rc);
        SetBkMode(hdc, TRANSPARENT);
        DrawText(hdc, szText, _tcslen(szText), &rc, DT_CENTER | DT_VCENTER);
        EndPaint(hwnd, &ps);
        return 0;
    }

      //v2 StaticWndProc(hwnd, Message, wparam, lparam);
    return CallWindowProc(StaticWndProc, hwnd, Message, wparam, lparam); //v2
}

HWND hWndStatic; //v2
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{   switch (Message)
    {   case WM_CREATE:
        {   LRESULT lRes = DefWindowProc(hwnd, Message, wparam, lparam);
            hWndStatic = CreateWindowEx(0, L"Static", NULL, WS_CHILD| WS_VISIBLE |SS_LEFT, 10, 130, 200, 40, hwnd, NULL, hInst, NULL); //v2 deleted HWND
            StaticWndProc = (WNDPROC) SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)MyStaticWndProc);
            return lRes;
        }

        case WM_DESTROY: 
            SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)StaticWndProc); //v2
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, Message, wparam, lparam);
    }

    return 0;
}
Edward Clements
  • 5,040
  • 2
  • 21
  • 27
  • I've tried the WM_CTLCOLORSTATIC route, it ended exactly where Owner Draw did. I'm not having any problems updating the text. The problem is, I can set the "text" parts background transparent no problem. But the actual static controls background I cannot. That one thing is what I have spent days and days trying to accomplish. It is literally possible for it to not be possible to do this... text background transparent and static controls background transparent. – Evan Carslake May 03 '14 at 07:57
  • I just realized... Creating the static control is, obviously, a window. The white is the solid background of the static window/ control. So I should be looking at how to make a windows background transparent... – Evan Carslake May 03 '14 at 08:20
  • 1
    There's no way prior to Windows 8 to make a child window truly transparent. The solution is to draw the underlying background image into your child window before rendering the text on top of it. – Jonathan Potter May 03 '14 at 08:34
  • 3
    Handling `WM_CTLCOLORSTATIC` will work just fine. You just return the same pattern brush you're using to draw the window's background. You might also need to call [`SetBrushOrgEx`](http://msdn.microsoft.com/en-us/library/windows/desktop/dd162967.aspx). – Cody Gray - on strike May 05 '14 at 07:37
  • The purpose of the hatched background was to display the "static controls" background. I could get the text background transparent, but could not get the controls background transparent. The screenshot was showing that I wanted the background(s) transparent, I was aiming for the right shot. – Evan Carslake May 05 '14 at 17:13
  • I updated my first post with the updated code. As is, there was a white box surrounding the text, though I couldn't change its color and it was not coming from the control. I removed CLIP_CHILDREN from the main window, and it worked. But in my main program, that makes all my custom drawn buttons and such disappear. – Evan Carslake May 05 '14 at 19:43
  • It's not very clear about your problem, but I noticed that you were setting `hInstance = hThisInstance;` after the call to `CreateWindowEx()`, it should be before (the main window proc will receive `WM_CREATE` when `CreateWindowEx()` is called); I have also updated my answer with the initial `WinMain()` function. – Edward Clements May 06 '14 at 06:06
  • Yeah, I suspected that the patterned background was just for demonstration purposes. Hopefully no one would really create something so ugly! I just wanted to point out that the assertion in the answer was not entirely correct—you can in fact use `WM_CTLCOLORSTATIC` with a patterned background. @evan – Cody Gray - on strike May 06 '14 at 07:22
  • 2
    Beyond that, @Edward, the code you show here for subclassing a control is incorrect. I should have noticed before, but I didn't look carefully. Two things immediately jump out at me. First, you are not *removing* the subclass before the control is destroyed. When you subclass, that becomes your obligation: clean up after yourself. Second, you are not using the `CallWindowProc` function, like the documentation says you're required to do. You aren't supposed to just call the proc directly. The docs on subclassing are [here](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633570.aspx). – Cody Gray - on strike May 06 '14 at 07:24
  • It works... Ill try to be more specific... With using the WM_CTLCOLORSTATIC and alikes, I could not get rid of the background. I can take the background from the text, but not the background from the static control. I'm looking for transparency. I don't want a static control and have it have the same background color or pattern to match the rest, I want text directly placed on it. The big issue now is that I rely on WS_CLIPCHILDREN, and with the window style, the statics background comes back again. I found some other stuff on google about clip regions and that seems to be the only way... – Evan Carslake May 06 '14 at 07:48
  • 1
    @CodyGray you're very right, thanks for your comments! I've edited my code (marked with `//v2`) – Edward Clements May 06 '14 at 09:45
  • 1
    @EvanCarslake, I'm still confused, are you now switching to a solid background colour and using `WM_CTLCOLORSTATIC`? in that case, the code from my struckout link at the top of the answer works even when `WS_CLIPCHILDREN` is included in the parent window style – Edward Clements May 06 '14 at 09:54
  • [I uploaded a new window shot to show you whats happening] Thanks. My bad for the confusion. I'm not using WM_CTLCOLORSTATIC. When I was, I found it impossible to remove the controls background, only the text. I got your version compiled, and I ended up with the same problem, the text had a transparent background, that was layed ontop of a solid color background, same problem. I removed WS_CLIPCHILDREN and it worked correctly. But in doing so, all other controls disappeared. – Evan Carslake May 06 '14 at 18:34
  • 1
    The code above relies on the parent drawing the background, but `WS_CLIPCHILDREN` prevents the parent window from drawing in the areas occupied by its children. This would not be a problem if your background is a solid colour (just handle `WM_ERASEBKGND` in the static wnd proc and fill the client rect using the background brush). With a hatched background, you would also need to fiddle with [SetBrushOrgEx](http://msdn.microsoft.com/en-us/library/windows/desktop/dd162967(v=vs.85).aspx) to get the hatched pattern aligned correctly for `WM_ERASEBKGND`, like what @CodyGray mentioned earlier. – Edward Clements May 07 '14 at 06:38
  • The reason for the hatched background was to show that the static controls background was opaque, I was trying for transparent. The real application of this was for the static controls to be over bitmaps/ drawn screen (in the main HDC.) So there really is no way to tell what is underneath the control... – Evan Carslake May 07 '14 at 07:06
  • 1
    WM_CTLCOLORSTATIC should work without problem, I have personally implemented this in dialogs that also use nine-grid skinning. You can create a fill brush from anything including bitmaps, patterns, and solid colours. – Matthew May 08 '14 at 12:52
  • Is a fill brush different than a normal brush? HBRUSH hbrbknd = CreateSolidBrush(hdc, RGB(0,100,200)); I have tried that in the return of that function, as well as the stock brush, hollow_brush. Still, the statics background remains. Were you using WS_CLIPCHILDREN window style? – Evan Carslake May 08 '14 at 22:39
  • I'm going to just add this. I think that there is no clean way to make the static behave as wanted. I'm just going to use TextOut() and skip the "static control" doing it. I tried out WS_EX_TRANSPARENT style on the main CreateWindowEx() function. My statics then showed how I wanted, when I was just using WM_CTLCOLORSTATIC (and returned a null brush.) With or without WS_CLIPCHILDREN, it was fine. But, if using SS_OWNERDRAW (as I do with most of my controls,) it fails. I suspect this is because WS_EX_TRANSPARENT just makes sure the WM_PAINT message goes first. – Evan Carslake May 09 '14 at 00:20
  • It fails for me because most of my stuff is drawn to a buffer DC and then BitBlt with a timer. My WM_PAINT message does no drawing at all. So, it is drawing the controls after WM_PAINT, and then gets overlapped with the BitBlt(), so I can't see them. I think that is what is happening because they flicker a bit if I click on them. – Evan Carslake May 09 '14 at 00:23