0

Here is what I'm talking about:program window

I know, this topic was several times published, but I can't find any good solution. My problem is
1.: -flickering controls showing time and histogram (static, not double bufferred).
2.: -I can't change background of controls (labels, trackbar buddies, histogram bkgnd) from white to LTGRAY_BRUSH.
And here's some code:

case WM_PAINT:
    PaintProcedure( hdcClock );
    SetBkColor(hdcWindow, RGB(255,220,180));
    TextOut(hdcWindow,260,10,TEXT(" -- CAMERA WINDOW -- "),21); 
    break;

... ...

void PaintProcedure( HDC hdc )
{
    img = cam->getFrame();
    cam->ShowImage(img, hdcCam, 1, 1, img->width, img->height, 0, 0);

    InvalidateRect( hClock, &rClock, 1 );               
    RedrawWindow(hClock,&rClock,0,RDW_UPDATENOW);

    char sTime[256];
    SYSTEMTIME time;
    HFONT hFont;
    SIZE size;
    ...
        ...
    BeginPath (hdc) ;
    SetBkMode( hdc, TRANSPARENT/*OPAQUE*/ );
    TextOut( hdc,1,1,sTime, strlen( sTime ) );
    EndPath (hdc) ;

    SelectObject (hdc, CreateHatchBrush (HS_DIAGCROSS, RGB (0, 0, 255))) ;
    SetBkColor (hdc, RGB (255, 0, 0)) ;
    SetBkMode (hdc, OPAQUE) ;

    StrokeAndFillPath (hdc) ;
    DeleteObject (SelectObject (hdc, GetStockObject (LTGRAY_BRUSH)));
    SelectObject (hdc, GetStockObject (SYSTEM_FONT)) ;
    DeleteObject (hFont) ;

    cam->ShowImage(cam->drawIntensityHistogram(),hdcHistogram,1,1,
        rHistogram.right-rHistogram.left,rHistogram.bottom-rHistogram.top,0,0);


    InvalidateRect( hwnd, &r, 1 );
    RedrawWindow(hwnd,&r,0,RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
}

Adding this code:

case WM_CTLCOLORSTATIC:
case WM_CTLCOLORDLG:
case WM_CTLCOLORBTN:
    return (LRESULT)GetStockObject(LTGRAY_BRUSH);

causes that only trackbars are drawn without a frame. I tried to use timers to invalidate and redraw controls but it doesn't help. Now I have no idea how to fix it. Could someone help me, please?

Andrzej Krynski
  • 71
  • 3
  • 13
  • Is your main window a dialog box, or do you create the window and its controls yourself? [if it is a dialog box, you could probably handle the drawing when the timer fires, no need to handle `WM_PAINT`] – Edward Clements Mar 22 '14 at 10:08
  • The window and all controls are 'self-made'. I create controls on WM_CREATE message. And main window has CS_OWNDC flag set. case WM_CREATE: hdcWindow = GetDC (hwnd) ; hClock = CreateWindowEx( 0, "STATIC", NULL, WS_CHILD |WS_BORDER |WS_VISIBLE, 10, 4, 100, 25, hwnd, NULL, hInst, NULL ); – Andrzej Krynski Mar 22 '14 at 15:35
  • I would recommend removing the handler for `WM_PAINT` and call your `PaintProcedure()` when the timer fires, remove all calls to `InvalidateRect()` and `RedrawWindow()`from your `PaintProcedure()` and use your different `HDC`s to paint to your controls – Edward Clements Mar 22 '14 at 15:46
  • In this way it draws nothing: https://www.dropbox.com/s/t0thgwhzws0einv/follower1.png – Andrzej Krynski Mar 22 '14 at 17:13

3 Answers3

0

Remove the handler for WM_PAINT and call your PaintProcedure() when the timer fires: sample code

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

    memset(&w,0,sizeof(WNDCLASS));
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc;
    w.hInstance = hInstance;
    w.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); // WHITE_BRUSH
    w.lpszClassName = L"My Class";
    w.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&w);
    hwnd = CreateWindow(L"My Class", L"My title", WS_OVERLAPPEDWINDOW, 300, 200, 800, 600, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);

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

UINT_PTR uTimerId;
LOGBRUSH lbrBk;
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{   switch (Message)
    {   case WM_CREATE:
        {   LRESULT lRes = DefWindowProc(hwnd, Message, wparam, lparam); // I don't have any controls in the main window
            HBRUSH hbr = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
            GetObject(hbr, sizeof(lbrBk), &lbrBk); // for use in timer logic
            uTimerId = SetTimer(hwnd, 123, 1000, NULL);
            return lRes;
        }

        case WM_TIMER:
        {   TCHAR szTime[128];
            HDC hdc = GetDC(hwnd);
            _tstrtime_s(szTime, _countof(szTime));
            SetBkColor(hdc, lbrBk.lbColor);
            TextOut(hdc, 200, 200, szTime, _tcslen(szTime));
            ReleaseDC(hwnd, hdc);
            break;
        }

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

        default:
            return DefWindowProc(hwnd, Message, wparam, lparam);
    }
    return 0;
}
Edward Clements
  • 5,040
  • 2
  • 21
  • 27
0

Oh, I was not using winapi since years, so I could forget how gdi works, but I don't understand how could I not get it, you was talking about: remove WM_PAINT - the whole handler, not only the calls I do from it.
Earlier I solved problem with histogram flickering. It is very fast procedure, all algorithms in camera class I wrote and checked in python, so I was sure it should work. And it works. I had to turn off code optimalization.
Your tip solves timer flickering problem and overall interface efficiency. But there is now not solved white background problem. Should I use subclassing to give my controls the color of my choice? I tried on WM_CREATE

hStatic = CreateWindowEx( 0, "STATIC", NULL, WS_CHILD| WS_VISIBLE |SS_LEFT, 10, 130, 200, 20, hwnd, NULL, hInst, NULL );
        SetBkColor(GetDC(hStatic), lbrBk.lbColor);
        SetWindowText( hStatic, buf );

but without an effect.
Here is my interface looks like now: https://www.dropbox.com/s/7123ef7wi1sars8/follower2.png
Thank you. :D

Andrzej Krynski
  • 71
  • 3
  • 13
  • You will need to either call `SetBkColor()` before each `TextOut()` [not sure if using global HDC variables and calling `SetBkColor()` om `WM_CREATE` will also work] – Edward Clements Mar 23 '14 at 11:34
  • as you see on_create it doesn't work, I'll try to play with it on evening. – Andrzej Krynski Mar 23 '14 at 12:06
  • After changing WM_CTLCOLORSTATIC return value to (LRESULT)CreateSolidBrush(RGB(0,0,255)) I see that bacground of control was correctly chanded to LTGRAY (blue now). The white background of text on controls is simply ***font background!*** – Andrzej Krynski Mar 23 '14 at 15:19
  • I see, there is no way to change text background using system procedures. System simply makes various bool operations when SetWindowText() occurs, using predefined colors. I HAVE TO use control's subclassing to have this what I want. I don't set topic as solved untill I am ready with this. Again, thanks for help. Any further remarks are well seen :D – Andrzej Krynski Mar 24 '14 at 08:49
  • I'm not very sure I understand what you are asking, but in your `WM_CTLCOLORSTATIC` handler you can return a brush depending on the control e.g.: `if ((HWND)lParam == hWndClock)` – Edward Clements Mar 24 '14 at 09:00
  • Sorry my poor english. You're right. This brush is used to change control's background but the color of text background drawn on those controls remains unchanged. In this case white. I mean all those texts: 'Tools','Contrast','0','100' ect. And I want this have TRANSPARENT. ***SetBkMode( hdcOfControl, TRANSPARENT );*** doesn't change background in this case although it works in PaintProcedure with my clock control. – Andrzej Krynski Mar 24 '14 at 09:24
  • the `TRANSPARENT` mode will render your new text "on top of" the old text, so it not look good -- in my previous answer, there is no `TRANSPARENT` mode, the background colour is set by returning a brush of the correct colour for that control – Edward Clements Mar 24 '14 at 09:42
  • sorry, maybe I misunderstood your question -- try `SetBkColor()` in your `WM_CTLCOLORSTATIC` handler? – Edward Clements Mar 24 '14 at 09:52
  • setting transparent or opaque or without setting any mode - it changes nothing – Andrzej Krynski Mar 24 '14 at 10:05
  • I decided to show full code. Sorry, but it is a bit messy.[link](http://pastebin.com/5Yu9PZBG) – Andrzej Krynski Mar 24 '14 at 10:32
  • Sorry, I don't have time to go through your full source, please see new answer using a static control – Edward Clements Mar 24 '14 at 11:39
  • SURE. Man, it works! Thank you very much, especially for the patience ;) – Andrzej Krynski Mar 24 '14 at 12:13
0

Source code using a static control:

LONG WINAPI WndProc(HWND, UINT, WPARAM,LPARAM);

HWND hWndStatic;

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

    memset(&w,0,sizeof(WNDCLASS));
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc;
    w.hInstance = hInstance;
    w.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
    w.lpszClassName = L"My Class";
    w.hCursor = LoadCursor(NULL, IDC_ARROW); 
    RegisterClass(&w);

    hwnd = CreateWindow(L"My Class", L"My title", WS_OVERLAPPEDWINDOW, 300, 200, 800, 600, NULL, NULL, hInstance, NULL);
    hWndStatic = CreateWindowEx(0, L"Static", NULL, WS_CHILD| WS_VISIBLE |SS_LEFT, 10, 130, 200, 20, hwnd, NULL, hInstance, NULL);

    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);

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

UINT_PTR uTimerId;
LOGBRUSH lbrBk;

LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
    switch (Message)
    {   case WM_CREATE:
        {   LRESULT lRes = DefWindowProc(hwnd, Message, wparam, lparam);
            HBRUSH hbr = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
            GetObject(hbr, sizeof(lbrBk), &lbrBk);
            uTimerId = SetTimer(hwnd, 123, 1000, NULL);
            return lRes;
        }

        case WM_CTLCOLORSTATIC:
            if ((HWND)lparam == hWndStatic)
            {   SetBkColor((HDC)wparam, lbrBk.lbColor);
                return (BOOL) GetStockObject(LTGRAY_BRUSH);
            }
            return FALSE;

        case WM_TIMER:
        {   TCHAR szTime[128];
            HDC hdc = GetDC(hwnd);
            _tstrtime_s(szTime, _countof(szTime));
            SetWindowText(hWndStatic, szTime);
            ReleaseDC(hwnd, hdc);
            break;
        }

        case WM_DESTROY: 
            KillTimer(hwnd, uTimerId);
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, Message, wparam, lparam);
    }
    return 0;
}
Edward Clements
  • 5,040
  • 2
  • 21
  • 27