Qt working Windows 8 style frameless custom window

前端 未结 2 668
梦谈多话
梦谈多话 2021-01-06 10:03

I recently installed Github for Windows on my Windows 7 machine and loved the custom frame it had, it fit really well with the overall application theme and had it\'s own ti

2条回答
  •  旧巷少年郎
    2021-01-06 10:48

    Minimize window by clicking on task bar

    It seems that Qt::FramelessWindowHint's implementation is limited. When this flag is set, Windows thinks that this window cannot be minimized or maximized. I've tried this solution implemented in pure winapi. Minimizing and restoring frameless window by clicking on taskbar works fine. Apparently Qt sets some bad flags that block this functionality. May be there is a good reason for that, I don't know.

    We can use winapi and Qt together but it is troublesome. Firstly, winapi code should be executed after you set window flags and show the window using Qt. Otherwise Qt will overwrite window flags.

    Another problem is when we remove border using winapi, window geometry suddently changes, and Qt doesn't know about that. Rendering and event mapping (including mouse click positions) become invalid. I didn't find any documented way to update mapping. I've found that we can tell Qt that screen orientation has changed, and it forces it to recalculate window geometry. But this looks like a dirty hack. Also the QWidget::windowHandle function is missing in Qt 4 and "is subject to change" in Qt 5. So this method is not reliable. But anyway, it works now. Here is complete code (tested in Windows 8) that should be placed in the top window class constructor:

    #include "windows.h"
    #include 
    //...
    show();
    HWND hwnd = reinterpret_cast(effectiveWinId());
    LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
    lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
    SetWindowLong(hwnd, GWL_STYLE, lStyle);
    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
    windowHandle()->reportContentOrientationChange(Qt::PrimaryOrientation);
    

    The true way to solve this problem is to modify the Window Qt platform plugin (see QWindowsWindow class in Qt sources). May be there is a way to inherit from the default implementation, modify it and use in your app. Also you can ask Qt developers is this behavior reasonable or is it a bug. I think that this issue can be fixed with a patch.

    If you still intend to use this code and other OSs should be also supported, don't forget to wrap windows-specific implementation in #ifdef Q_OS_WIN.

    Enable window dragging only when title bar is clicked and window is not maximized

    Other problems can be fixed more easily. When you process mouse events to implement window dragging, check window state and event position and disable moving when it is unwanted.

    void MainWindow::mousePressEvent(QMouseEvent *e) {
      if (!isMaximized() && 
          e->button() == Qt::LeftButton && 
          ui->title->geometry().contains(e->pos())) {
        window_drag_start_pos = e->pos();
      }
    }
    
    void MainWindow::mouseReleaseEvent(QMouseEvent *e) {
      window_drag_start_pos = QPoint(0, 0);
    }
    
    void MainWindow::mouseMoveEvent(QMouseEvent *e) {
      if (!window_drag_start_pos.isNull()) {
        move(pos() + e->pos() - window_drag_start_pos);
      }
    }
    
    void MainWindow::on_minimize_clicked() {
      showMinimized();
    }
    
    void MainWindow::on_maximize_clicked() {
      if (isMaximized()) {
        showNormal();
      } else {
        showMaximized();
      }
    }
    

    Here ui->title is a label used for displaying fake title bar, and QPoint window_drag_start_pos is a class variable.

提交回复
热议问题