Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qt Application in native Windows window

Qt Application in native Windows window

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 8.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    Jake007
    wrote on 14 Jul 2013, 14:30 last edited by
    #1

    Hi!

    Is it possible to render Qt GUI application inside a native Windows window?
    I'd like to have better control over windows frame, which I find impossible to do just with Qt.

    Thanks in advance.

    Regards,
    Jake


    Code is poetry

    1 Reply Last reply
    0
    • C Offline
      C Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on 14 Jul 2013, 18:55 last edited by
      #2

      While it's possible to embed QWidget in external window it's a waste of time since it already has a native frame, so you'd be doing the same thing Qt does anyway.

      To get a grip on the Windows windowing stuff(the frame in your case) you basically need access to HWND of the window and the MSG messages it receives from the system.

      You can get HWND of the window by casting the result of "winId":http://qt-project.org/doc/qt-5.1/qtwidgets/qwidget.html#winId, and then implement the "nativeEvent":http://qt-project.org/doc/qt-5.1/qtwidgets/qwidget.html#nativeEvent and cast the message param to MSG.

      1 Reply Last reply
      0
      • J Offline
        J Offline
        Jake007
        wrote on 14 Jul 2013, 21:57 last edited by
        #3

        Hi!

        Thanks.
        I already figured a small part of it in the mean time, but I'm still having some difficulties.

        The problem that I have is just a border around it. When a window is displayed, the border is still shown and then when it is resized, border disappears but it leaves not rendered white area around the window.

        Bottom area is exact height as the title bar + bottom border and right area 2*border width.

        Link to image "here":http://oi44.tinypic.com/2j8ayo.jpg.
        Black area: entire screen cropped out a little bit
        Blue and green window custom border
        White with a little blue and green on the left is the area: problems.
        Window is already resized at this point.

        It's still in debug colours, so it's not yet a Picaso masterpiece ;).

        I'm trying to port the code from "here":http://msdn.microsoft.com/en-us/library/windows/desktop/bb688195(v=vs.85).aspx msdn article (missing ").aspx" in the URL address).

        Regards,
        Jake

        Code:
        @bool Window::nativeEvent(const QByteArray &eventType, void *message, long *result)
        {
        *result = 0;
        MSG *msg = static_cast<MSG *>(message);

        if(msg->message == WM_CREATE)
        {
        HWND hWnd = (HWND)this->winId();
        qDebug() << "WM_ACTIVATE";

        RECT rcClient;
        GetWindowRect(hWnd, &rcClient);

        SetWindowPos(hWnd,
        NULL,
        this->pos().x(), this->pos().y(),
        this->size().width(), this->size().height(),
        SWP_FRAMECHANGED);

        *result = 0;
        }

        else if(msg->message == WM_ACTIVATE)
        {
        qDebug() << "WM_ACTIVATE";

        HWND hWnd = (HWND)this->winId();
        MARGINS margins;

        margins.cxLeftWidth = 0;
        margins.cxRightWidth = 0;
        margins.cyBottomHeight = 0;
        margins.cyTopHeight = 0;

        DwmExtendFrameIntoClientArea(hWnd, &margins);

        *result = 0;
        }

        else if(msg->message == WM_NCCALCSIZE)
        {
        qDebug() << "WM_NCCALCSIZE";

        NCCALCSIZE_PARAMS pncsp = reinterpret_cast<NCCALCSIZE_PARAMS>(msg->lParam);

        pncsp->rgrc[0].left = pncsp->rgrc[0].left + 0;
        pncsp->rgrc[0].top = pncsp->rgrc[0].top + 0;
        pncsp->rgrc[0].right = pncsp->rgrc[0].right - 0;
        pncsp->rgrc[0].bottom = pncsp->rgrc[0].bottom - 0;
        }

        else
        return QWidget::nativeEvent(eventType, message, result);
        }@

        EDIT:
        Includes
        @#pragma comment(lib, "dwmapi.lib")
        #pragma comment(lib, "UxTheme.lib")
        #include <dwmapi.h>
        #include <UxTheme.h>
        #include <WindowsX.h>
        #include "strsafe.h"
        #include <afxres.h>
        #include <Windows.h>@


        Code is poetry

        1 Reply Last reply
        0
        • C Offline
          C Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on 14 Jul 2013, 22:42 last edited by
          #4

          Seems like some of the stuff is interfering with Qt. For example you use SetWindowPos with HWND, when there's simply resize() and move() on the QWidget. They might fight each other and it's just better to use the Qt ones.

          I'm not clear on what you try to do exactly, but here's what I do to extend a frame on a widget:
          @
          bool extendAeroFrame( QWidget *widget, QMargins margins )
          {
          //magic number should be propagated to all sides
          if( margins.left() == -1 || margins.right() == -1 || margins.top() == -1 || margins.bottom() == -1 )
          margins = QMargins( -1, -1, -1, -1 );

          BOOL compositionEnabled;
          DwmIsCompositionEnabled( &compositionEnabled );
          
          if( compositionEnabled )
          {
              MARGINS mrg;
              mrg.cxLeftWidth = margins.left();
              mrg.cxRightWidth = margins.right();
              mrg.cyTopHeight = margins.top();
              mrg.cyBottomHeight = margins.bottom();
          
              HRESULT hr = DwmExtendFrameIntoClientArea( (HWND)widget->winId(), &mrg );
              widget->repaint();
              return SUCCEEDED( hr );
          }
          else
          {
              widget->repaint();
              return false;
          }
          

          }
          @

          An important thing is to check if "Aero" is enabled at all, and also watch for WM_DWMCOMPOSITIONCHANGED message that comes whenever used changes theme. Not watching this results in some nasty drawing artifacts after the switch.

          Now the tricky part is that we have to actually paint the background to "transparent" color. Otherwise Qt will just fill it for us with it's style color disregarding the actual margins the above method sets.
          To do this reimplement paintEvent and replace the margins with transparency.
          Something like this (writing out of my head so expect bugs):
          @void YourWidget::paintEvent(QPaintEvent * event)
          {
          QWidget::paintEvent( event );

          if(aero_is_enabled) //use DwmIsCompositionEnabled
          {
          QPainter p( this );
          p.setCompositionMode( QPainter::CompositionMode_SourceIn );
          p.fillRect( topMargin, Qt::transparent );
          p.fillRect( bottomMargin, Qt::transparent );
          p.fillRect( leftMargin, Qt::transparent );
          p.fillRect( rightMargin, Qt::transparent );
          p.setCompositionMode( QPainter::CompositionMode_SourceOver );
          }
          }
          @

          That's if you want to extend the frame inside the widget.

          If you don't want the frame at all and want to draw it yourself it's easier to create a borderless "frame" widget (set a Qt::FramelessWindowHint flag on it), set a layout with margins that you want your window to have and override paintEvent to draw, and mouse event like press, move and release to handle resizing, or better yet - an event filter. This is more portable and actually easier than fiddling with low level winapi stuff.

          Btw. MSDN links are a pain to put on this forum(and some others), but just remove the (v=vs.85) part and they work just fine.

          1 Reply Last reply
          0
          • J Offline
            J Offline
            Jake007
            wrote on 15 Jul 2013, 06:01 last edited by
            #5

            That's the thing. I don't want the frame at all.
            It tried with Qt::FramelessWindowHint. Problem that I have with that option is that I can't capture windows btn + arrow keys to resize and move a window. That forced me to fallback to winapi stuff.

            MSDN (thanks for the link tip) example works fine, that's why I tried integrating win32 window from winapi with Qt.

            EDIT:
            I tried cheking button states with GetKeyboardState, GetAsyncKeyState and GetKeyState. All return 0 if Windows button is pressed.

            "Here":https://www.dropbox.com/s/pnur0irvvhld2qr/CustomWindow.zip is a link to entire project.


            Code is poetry

            1 Reply Last reply
            0

            5/5

            15 Jul 2013, 06:01

            • Login

            • Login or register to search.
            5 out of 5
            • First post
              5/5
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved