How to draw to the windows Title Bar with Qt? Is this possible?



  • Hi,

    for our project, I have to change the Titlebar look and feel of the application (including the app buttons, minimize etc.). Is there a way to do this with Qt? Is it possible to use Qt in WM_NCPAINT with some tricks?

    I know, it's possible by overwriting WM_NCPAINT message and drawing with windows SDK, but's a bit uncomfortable, especially, as I need gradients.

    I'm using Qt 4.6.3 and MSVS 2008 on windows XP, 2008 Server R1, Windows 7.



  • Ok, I have one solution, although it's not the best and currently does not do the Application icon and the Titlebar buttons, but I'm sure, it will also be solvable....

    This is my simple widget, just a bit of a Gradient :-)
    @
    void Widget::paintEvent(QPaintEvent*)
    {
    QPainter paint(this);

    paint.fillRect(rect(), QColor(0,180,0));
    
    QLinearGradient grad(0,0,0,rect().height());
    grad.setColorAt(0, QColor(255,255,255,180));
    grad.setColorAt(0.33, QColor(255,255,255,80));
    grad.setColorAt(0.33, QColor(255,255,255,0));
    grad.setColorAt(1, QColor(255,255,255,0));
    paint.fillRect(rect(), grad);
    

    }
    @

    To draw the window frame, you have to overwrite WM_NCPAINT on Windows

    @
    bool Widget::winEvent(MSG* pMessage, long *result)
    {
    if(pMessage->message == WM_NCPAINT)
    {
    paintPicture(pMessage, result);
    return true;
    }
    return QWidget::winEvent(pMessage, result);
    }
    @

    I decided to draw everything into a picture and blit this picture on the screen. This way I have the complete possibilities of Qt for drawing (like Gradients etc.) and can draw into the window frame. The code is not really documented :-) as it's test code. If you have any questions about the sollution, feel free to ask...

    Perhaps I will craete a wiki page if I managed the rest of the title bar like the buttons...

    @
    void Widget::paintPicture(MSG* pMessage, long *result)
    {
    RECT winRect1;
    RECT winRectCl;
    ::GetWindowRect(winId(), &winRect1);
    ::GetClientRect(winId(), &winRectCl);
    HDC hDeviceContext = ::GetWindowDC(winId());
    LONG lStyle = ::GetWindowLong(winId(), GWL_STYLE);

    POINT ptTopLeft = {winRectCl.left, winRectCl.top};
    POINT ptBottomRight = {winRectCl.right, winRectCl.bottom};
    
    ::ClientToScreen(winId(), &ptTopLeft);
    ::ClientToScreen(winId(), &ptBottomRight);
    winRectCl.left = ptTopLeft.x - winRect1.left;
    winRectCl.top = ptTopLeft.y - winRect1.top;
    winRectCl.right = ptBottomRight.x - winRect1.left;
    winRectCl.bottom = ptBottomRight.y - winRect1.top;
    
    winRect1.right = winRect1.right - winRect1.left;
    winRect1.bottom = winRect1.bottom - winRect1.top;
    winRect1.top = 0;
    winRect1.left = 0;
    
    HRGN hRgnOuter = ::CreateRectRgn(winRect1.left, winRect1.top, winRect1.right, winRect1.bottom);
    HRGN hRgnInner = ::CreateRectRgn(winRectCl.left, winRectCl.top, winRectCl.right, winRectCl.bottom);
    HRGN hRgnCombine = ::CreateRectRgn(winRect1.left, winRect1.top, winRect1.right, winRect1.bottom);
    
    ::CombineRgn(hRgnCombine, hRgnOuter, hRgnInner, RGN_DIFF);
    ::SelectClipRgn(hDeviceContext, hRgnCombine);
    
    QPixmap pix(winRect1.right, winRect1.bottom);
    QPainter paint(&pix);
    QRect rc(0,0,winRect1.right, winRect1.bottom);
    
    paint.fillRect(rc, QColor(28,28,28));
    QLinearGradient grad(0,0,0,40);
    grad.setColorAt(0, QColor(255,255,255,180));
    grad.setColorAt(0.33, QColor(255,255,255,80));
    grad.setColorAt(0.33, QColor(255,255,255,0));
    grad.setColorAt(1, QColor(255,255,255,0));
    paint.fillRect(QRect(0,0,winRect1.right, 40), grad);
    
    HBITMAP hBmp = pix.toWinHBITMAP();
    HDC hDC = ::CreateCompatibleDC(hDeviceContext);
    ::SelectObject(hDC, hBmp);
    ::BitBlt(hDeviceContext, winRect1.left, winRect1.top, winRect1.right, winRect1.bottom, hDC, 0, 0, SRCCOPY);
    ::DeleteDC(hDC);
    ::DeleteObject(hBmp);
    
    ::DeleteObject(hRgnOuter);
    ::DeleteObject(hRgnInner);
    ::DeleteObject(hRgnCombine);
    ::ReleaseDC(winId(), hDeviceContext);
    *result = 0;
    

    }
    @



  • Hello, is it possible for you to post some more code? I mean what libs are you #including? I tried your code in my program and I am getting linker error:

    @debug/nmainwindow.o:J:\nts (1).tar\ns (1)\ns-build-desktop/../ts/nindow.cpp:150: undefined reference to `CreateRectRgn16'@

    etc.. But I am including "windows.h" and "wingdi.h", I have also tried #define FL_DLL.

    Thank You,
    Mazur



  • I did nothing special for that. It's not an #include thing, it's the library you need. If you want to know, which lib is needed, go to "MSDN":http://msdn.microsoft.com/en-us/ and search for the function, that is missed. It should display, which library to use, which must be done in the pro file.

    But the show solution does not work completely, it does not how the app icon, the buttons are definitely incorrect etc...



  • By the way, for CreateRectRgn it should be something like

    @
    LIBS += -lGdi32
    @

    which must be added to the project file



  • Basically :

    use @setWindowFlags(Qt::FramelessWindowHint);@ on your top window, this will remove the OS generated window frame.

    Then simply creates a widget that does what you want for example vertical layout with custom title bar widget and your central widget. Retrieve move events from your titlebar widget and reimplement the window movement etc...

    There's a good tutorial in here but in French (maybe try automatic translation) or go directly into the source code of the tutorial which is commented in English.
    "Lien vers le Tuto":http://qt.developpez.com/tutoriels/braindeadbzh/customwindow/



  • That's not really a solution, I already tried this.

    There is some impact (especially on windows):

    • a windows without a title bar can't be maximized, only full screen, if you call maximize, it will become full screen (windows specifica)
    • implementing the system menu must be done by hand for the title bar
    • a system menu on right click in the windows tab pane is always incorrect as the states are not know by windows correctly, changing them does not really work
    • If you do maximizing by hand and only use the client area of the screen, you can resize the window (from windows point of view).

    That's why changing the NC paint makes more sense on MS Windows



  • Ok if you need all windows specs, it's different. But as it is windows itself that paint the windows title bar, it nothing about Qt to draw on it I suppose ? Just windows code as you are talking about. Won't be cross platform.

    What is the point of having a custom title bar if you need all windows specific menus and functions, why not keep the windows defaults ?



  • Perhaps you want a custom look and feel and perhaps more buttons. I know it's possible and we need it for our Cooperate design etc.

    I know that using windows specifica is not cross platform, but some things will never work cross platform :-(

    And user expect programs on platform to behave like others on those platform...



  • Due to the same discussion in another thread, I close this one:

    "Painting in the NonClientArea":http://developer.qt.nokia.com/forums/viewthread/3847/

    [EDIT: wrong link, Volker]


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.