YOKO
YOKO

Reputation: 119

A label whose background is transparent on the one hand and the upper window on the other

I am currently building a ProgressBar in WinApi I want the caption "Loading" to appear on it.

I managed to create a label that would have a transparent background but I can not make the caption to be higher than the ProgressBar window.

This is my code:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{
    static HWND hwndPrgBar;
    static HWND lable;
    static int i = 1;
    HDC hdcStatic = NULL;

    INITCOMMONCONTROLSEX InitCtrlEx;

    InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
    InitCtrlEx.dwICC = ICC_PROGRESS_CLASS;
    InitCommonControlsEx(&InitCtrlEx);

    switch (msg)
    {
    case WM_CREATE:
        CenterWindow(hwnd);
        /* creating the progress bar */
        hwndPrgBar = CreateWindowEx(0, PROGRESS_CLASS, NULL,
            WS_CHILD | WS_VISIBLE | PBS_SMOOTH | PBS_MARQUEE, // pbs_smooth makes no difference when manifest sets new windows styles
            0, 0, 350, 25, hwnd, NULL, g_hinst, NULL);

        /* sets progress bar looks */
        SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(hwndPrgBar));
        SendMessage(hwndPrgBar, (UINT)PBM_SETBKCOLOR, 0, RGB(224, 224, 224));
        SendMessage(hwndPrgBar, (UINT)PBM_SETBARCOLOR, 0, (LPARAM)RGB(131, 203, 123)); 
        SendMessage(hwndPrgBar, (UINT)PBM_SETMARQUEE, (WPARAM)TRUE, (LPARAM)5);

        /* create the lable as child of prgress bar */
        lable = CreateWindowEx(WS_EX_TRANSPARENT, L"STATIC", L"", WS_CHILD | WS_VISIBLE | SS_LEFT | WS_SYSMENU, 140, 5, 100, 100, hwnd, (HMENU)(100), (HINSTANCE)GetWindowLong(hwndPrgBar, GWL_HINSTANCE), NULL);

        /* sets lable text to Loading */
        SendMessage(lable, WM_SETTEXT, NULL, (LPARAM)L"Loading");
        SetWindowPos(lable, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

        /* I have tried this lines -> it didn't worked
        SetForegroundWindow(lable);
        BringWindowToTop(lable);
        SetActiveWindow(lable);
        SwitchToThisWindow(lable, TRUE);
        SetWindowPos(lable, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 
        */

        /* set progress bar components */
        SendMessage(hwndPrgBar, PBM_SETRANGE, 0, MAKELPARAM(0, 150));
        SendMessage(hwndPrgBar, PBM_SETSTEP, 1, 0);

        /* start prorgess bar */
        i = 1;
        SendMessage(hwndPrgBar, PBM_SETPOS, 0, 0); 
        SetTimer(hwnd, ID_TIMER, 100, NULL); 

        break;


    case WM_TIMER:
        SendMessage(hwndPrgBar, PBM_STEPIT, 0, 0);
        i++;
        if (i == 150)
        {
            KillTimer(hwnd, ID_TIMER);
            exit(0);
        }
        break;

    case WM_COMMAND:
        break;

    case WM_DESTROY:
        KillTimer(hwnd, ID_TIMER);
        PostQuitMessage(0);
        break;

    case WM_CTLCOLORSTATIC:
        /* makes the lable transperent*/
        hdcStatic = (HDC)wParam;
        SetTextColor(hdcStatic, RGB(0, 0, 0));
        SetBkMode(hdcStatic, TRANSPARENT);

        return (LRESULT)GetStockObject(NULL_BRUSH);
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

How can I make a label on one side have a transparent background and on the other hand it will be above the progress bar?

Upvotes: 2

Views: 171

Answers (1)

Barmak Shemirani
Barmak Shemirani

Reputation: 31599

Handling WM_CTLCOLORSTATIC will work, but you have to invalidate label each time the progress bar changes the background:

case WM_TIMER:
    SendMessage(hwndPrgBar, PBM_STEPIT, 0, 0);
    InvalidateRect(lable, NULL, FALSE);
    ...

Or using subclass instead (remove the static control):

LRESULT CALLBACK PrgBarProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
    UINT_PTR, DWORD_PTR)
{
    switch(msg) {
    case WM_PAINT:
    {
        LRESULT lres = DefSubclassProc(hwnd, msg, wp, lp);
        HDC hdc = GetDC(hwnd);
        RECT rc;
        GetClientRect(hwnd, &rc);
        SetBkMode(hdc, TRANSPARENT);
        DrawText(hdc, L"Text", -1, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
        ReleaseDC(hwnd, hdc);
        return lres;
    }
    case WM_NCDESTROY:
        RemoveWindowSubclass(hwnd, SubclassProc, 0);
        return DefSubclassProc(hwnd, msg, wp, lp);
    }
    return DefSubclassProc(hwnd, msg, wp, lp);
}

...
SetWindowSubclass(hwndPrgBar, PrgBarProc, 0, 0);

PBS_MARQUEE forces the bar to go back and forth. You don't want that here. And it won't work unless visual styles are enabled through the manifest file, or the following lines in Visual Studio:

#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

Upvotes: 2

Related Questions