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. Customize window frame
Forum Updated to NodeBB v4.3 + New Features

Customize window frame

Scheduled Pinned Locked Moved Unsolved General and Desktop
12 Posts 8 Posters 46.2k Views 2 Watching
  • 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.
  • Chris KawaC Offline
    Chris KawaC Offline
    Chris Kawa
    Lifetime Qt Champion
    wrote on last edited by
    #3

    No, it's not. QStyle is for providing custom styles to the widgets. Window frame is an OS specific thing (some OSs don't have frames or windows) and is not drawn by Qt.

    On Windows you need to dive a little lower level than Qt offers, by responding to the native messages your window is getting. Implement the "nativeEvent":http://qt-project.org/doc/qt-5.0/qtwidgets/qwidget.html#nativeEvent and handle messages like "WM_NCPAINT":http://msdn.microsoft.com/pl-pl/library/windows/desktop/dd145212.aspx and "WM_NCHITTEST":http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618.aspx
    Google for "drawing in non-client area", just keep in mind that it's not a Qt specific task.

    Other approach is disabling window frame entirely by setting Qt::FramelessWindowHint flag on your widget, and drawing the frame and buttons yourself. This gives you the ultimate control of the look of the frame, but is also a lot of work, because you need to handle all the windowing behavior like resizing, moving, maximizing or Aero Shake yourself.

    1 Reply Last reply
    1
    • B Offline
      B Offline
      bodzio131
      wrote on last edited by
      #4

      Uuups, I misunderstood the problem. Thanks for clearing this!

      1 Reply Last reply
      0
      • A Offline
        A Offline
        Adelost
        wrote on last edited by
        #5

        Thanks! A bit harder than I had anticipated, but glad to know it's possible, even though it's OS specific.

        1 Reply Last reply
        0
        • raven-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by
          #6

          You don't really need to go that deep into the OS.

          Use "QWidget::setWindowFlags()":http://qt-project.org/doc/qt-4.8/qwidget.html#windowFlags-prop and set it to Qt::Window | Qt::FramelessWindowHint on your top-level widget.
          Now you need to do all the painting and handling (moving, resizing, minimizing, maximizing, closing) yourself, but this shouldn't be that hard to handle the specific events.

          EDIT: oops...sorry Krzysztof Kawa overread your last paragraph.

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          1 Reply Last reply
          0
          • S Offline
            S Offline
            Sam
            wrote on last edited by
            #7

            I dont know if this helps, but may be you can have a look at "Qt Tutorial: Creating a custom window":http://qt.developpez.com/tutoriels/braindeadbzh/customwindow/ , its in French just open the link in google chrome and it will translate to English.

            1 Reply Last reply
            0
            • T Offline
              T Offline
              TDHound
              wrote on last edited by A Former User
              #8
              #include "mainwindow.h"
              
              #ifdef Q_OS_WIN
              #include <WinUser.h>
              #include <windowsx.h>
              #include <dwmapi.h>
              #include <gdiplus.h>
              #include <GdiPlusColor.h>
              #endif
              
              MainWindow::MainWindow(QWidget *parent)
                  : QWidget(parent)
              {
                  setMinimumSize(450,405);
              }
              
              void MainWindow::showEvent(QShowEvent *event)
              {
                  QWidget::showEvent(event);
              #ifdef Q_OS_WIN
                  window_borderless();
              #endif
              }
              
              #ifdef Q_OS_WIN
              void MainWindow::window_borderless()
              {
                  if (isVisible())
                  {
                      //defaultStyle = (WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME)
                      SetWindowLongPtr(winId(), GWL_STYLE, WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX );
              
                      window_shadow();
              
                      SetWindowPos(winId(), 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
                  }
              }
              
              void MainWindow::window_shadow()
              {
                  const MARGINS shadow = { 1, 1, 1, 1 };
                  DwmExtendFrameIntoClientArea(winId(), &shadow);
              }
              
              bool MainWindow::winEvent(MSG *msg, long *result)
              {
                  switch (msg->message)
                  {
                  case WM_NCCALCSIZE:
                  {
                      //this kills the window frame and title bar we added with
                      //WS_THICKFRAME and WS_CAPTION
                      *result = 0;
                      return true;
                      break;
                  }
                  case WM_NCHITTEST:
                  {
                      *result = 0;
                      const LONG border_width = 8; //in pixels
                      RECT winrect;
                      GetWindowRect(winId(), &winrect);
              
                      long x = GET_X_LPARAM(msg->lParam);
                      long y = GET_Y_LPARAM(msg->lParam);
              
                      bool resizeWidth = minimumWidth() != maximumWidth();
                      bool resizeHeight = minimumHeight() != maximumHeight();
              
                      if(resizeWidth)
                      {
                          //left border
                          if (x >= winrect.left && x < winrect.left + border_width)
                          {
                              *result = HTLEFT;
                          }
                          //right border
                          if (x < winrect.right && x >= winrect.right - border_width)
                          {
                              *result = HTRIGHT;
                          }
                      }
                      if(resizeHeight)
                      {
                          //bottom border
                          if (y < winrect.bottom && y >= winrect.bottom - border_width)
                          {
                              *result = HTBOTTOM;
                          }
                          //top border
                          if (y >= winrect.top && y < winrect.top + border_width)
                          {
                              *result = HTTOP;
                          }
                      }
                      if(resizeWidth && resizeHeight)
                      {
                          //bottom left corner
                          if (x >= winrect.left && x < winrect.left + border_width &&
                                  y < winrect.bottom && y >= winrect.bottom - border_width)
                          {
                              *result = HTBOTTOMLEFT;
                          }
                          //bottom right corner
                          if (x < winrect.right && x >= winrect.right - border_width &&
                                  y < winrect.bottom && y >= winrect.bottom - border_width)
                          {
                              *result = HTBOTTOMRIGHT;
                          }
                          //top left corner
                          if (x >= winrect.left && x < winrect.left + border_width &&
                                  y >= winrect.top && y < winrect.top + border_width)
                          {
                              *result = HTTOPLEFT;
                          }
                          //top right corner
                          if (x < winrect.right && x >= winrect.right - border_width &&
                                  y >= winrect.top && y < winrect.top + border_width)
                          {
                              *result = HTTOPRIGHT;
                          }
                      }
              
                      //TODO: allow move?
                      if(*result==0)
                          *result = HTCAPTION ;
              
                      return true;
                      break;
                  } //end case WM_NCHITTEST
                  case WM_CLOSE:
                  {
                      return close();
                      break;
                  }
                  default:
                      return QWidget::winEvent(msg,result);
                  }
              
                  return false;
              }
              #endif
              
              1 Reply Last reply
              1
              • A Offline
                A Offline
                Adelost
                wrote on last edited by A Former User
                #9

                Interesting @TDHound. A bit beyond my understanding, but I guess you can do anything with the native window exposed if you know what you are doing.

                I tried out your code. I had to make some adjustments to make it work:

                #ifdef Q_OS_WIN
                #include <windows.h> // Fixes error C1189: #error :  "No Target Architecture"
                #include <WinUser.h>
                #include <windowsx.h>
                #include <dwmapi.h>
                #include <objidl.h> // Fixes error C2504: 'IUnknown' : base class undefined
                #include <gdiplus.h>
                #include <GdiPlusColor.h> 
                #pragma comment (lib,"Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved external symbol __imp__DwmExtendFrameIntoClientArea
                #endif
                

                Qt4
                This is what my result looks like in Qt4

                Framless native windows Qt4

                Qt5
                Any idea if it can work in Qt 5 as well? "winEvent()" has been replaced in Qt5 with nativeEvent(), and I made it compile by making some changes.

                bool MainWindow::nativeEvent(const QByteArray & eventType, MSG *msg, long *result) // Replaces winEvent()
                
                return QWidget::nativeEvent(eventType, msg, result); // Replaces winEvent()
                

                However it doesn't give the intended result.

                Framless windows Qt5

                1 Reply Last reply
                0
                • T Offline
                  T Offline
                  TDHound
                  wrote on last edited by
                  #10

                  See: https://bugreports.qt-project.org/browse/QTBUG-39268

                  1 Reply Last reply
                  0
                  • qwasder85Q Offline
                    qwasder85Q Offline
                    qwasder85
                    wrote on last edited by
                    #11

                    Whenever you use the FramelessWindowHint, you lose all Windows frame related features, such as docking, shortcuts, maximizing, etc.
                    You can implement some of them yourself, with great effort in some cases, other things will still just not work. Example: A frameless window cannot be maximized, it will instead go fullscreen, hiding the Windows task bar.
                    It's all a mess.

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      sbgk
                      wrote on last edited by
                      #12

                      That's why you explicitly override the native window style flags after setting Qt::FramelessWIndowHint. By restoring the style flags and handling the related native frame (nonclient area in Windows terms) events, you can have a custom frame (or no frame) and still retain the normal window behavior.

                      1 Reply Last reply
                      1

                      • Login

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