Asuka
Asuka

Reputation: 71

How to create frameless window style like VS2013 using QT5

My application window doesn't have a frame but it has the titlebar, minimize, maximize and close buttons as normal window, and when I drag the titlebar with the mouse it can move like other windows.

I can't find such style in QStyle, Q StyleSheet modules or even WindowExtras...

Someone tells me that QML can easily make it. Does that mean I should create the window with some resource image file (minimize, maximize and close buttons), make a titlebar using QML then disable the original window frame with C++ code?

Or is there any better ways to do it?

I'm new to qt, any suggestions will help.

Here are the shorcut links, my OS is Windows 7:

enter image description here

And:

enter image description here

Upvotes: 2

Views: 4111

Answers (2)

Jorgen
Jorgen

Reputation: 440

I created a small example, of how to create VS2013 like frameless window in Qt5: screenshot (mac) qt frameless window with dark style

You can get the complete sources here: https://github.com/Jorgen-VikingGod/Qt-Frameless-Window-DarkStyle

Otherwise here a show code overview of how to embed the "main" mainwindow into the "frameless" window. Also you can see how to add titlebar, buttons and do maximize, resize and move of the frameless window.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

/*
place your QMainWindow code here
*/
namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow
{
  Q_OBJECT
public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();
private:
  Ui::MainWindow *ui;
};

/*
this class is to add frameless window supoort and do all the stuff with titlebar and buttons
*/
class BorderlessMainWindow: public QMainWindow
{
  Q_OBJECT
public:
  explicit BorderlessMainWindow(QWidget *parent = 0);
  ~BorderlessMainWindow() {}
protected:
  void mouseMoveEvent(QMouseEvent* event);
  void mousePressEvent(QMouseEvent* event);
  void mouseReleaseEvent(QMouseEvent* event);
  void mouseDoubleClickEvent(QMouseEvent *event);
private slots:
  void slot_minimized();
  void slot_restored();
  void slot_maximized();
  void slot_closed();
private:
  MainWindow *mMainWindow;
  QWidget *mTitlebarWidget;
  QLabel *mWindowTitle;
  QPushButton *mMinimizeButton;
  QPushButton *mRestoreButton;
  QPushButton *mMaximizeButton;
  QPushButton *mCloseButton;
  QPoint mLastMousePosition;
  bool mMoving;
  bool mMaximized;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

/*
frameless window class: it adds the MainWindow class inside the centralWidget
*/
BorderlessMainWindow::BorderlessMainWindow(QWidget *parent) : QMainWindow(parent, Qt::CustomizeWindowHint ) {
  setObjectName("borderlessMainWindow");
  setWindowFlags(Qt::FramelessWindowHint| Qt::WindowSystemMenuHint);

  mMainWindow = new MainWindow(this);
  setWindowTitle(mMainWindow->windowTitle());

  QVBoxLayout *verticalLayout = new QVBoxLayout();
  verticalLayout->setSpacing(0);
  verticalLayout->setMargin(1);

  QHBoxLayout *horizontalLayout = new QHBoxLayout();
  horizontalLayout->setSpacing(0);
  horizontalLayout->setMargin(0);

  mTitlebarWidget = new QWidget(this);
  mTitlebarWidget->setObjectName("titlebarWidget");
  mTitlebarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  mTitlebarWidget->setLayout(horizontalLayout);

  mMinimizeButton = new QPushButton(mTitlebarWidget);
  mMinimizeButton->setObjectName("minimizeButton");
  connect(mMinimizeButton, SIGNAL(clicked()), this, SLOT(slot_minimized()));

  mRestoreButton = new QPushButton(mTitlebarWidget);
  mRestoreButton->setObjectName("restoreButton");
  mRestoreButton->setVisible(false);
  connect(mRestoreButton, SIGNAL(clicked()), this, SLOT(slot_restored()));

  mMaximizeButton = new QPushButton(mTitlebarWidget);
  mMaximizeButton->setObjectName("maximizeButton");
  connect(mMaximizeButton, SIGNAL(clicked()), this, SLOT(slot_maximized()));

  mCloseButton = new QPushButton(mTitlebarWidget);
  mCloseButton->setObjectName("closeButton");
  connect(mCloseButton, SIGNAL(clicked()), this, SLOT(slot_closed()));

  mWindowTitle = new QLabel(mTitlebarWidget);
  mWindowTitle->setObjectName("windowTitle");
  mWindowTitle->setText(windowTitle());

  horizontalLayout->addWidget(mWindowTitle);
  horizontalLayout->addStretch(1);
  horizontalLayout->addWidget(mMinimizeButton);
  horizontalLayout->addWidget(mRestoreButton);
  horizontalLayout->addWidget(mMaximizeButton);
  horizontalLayout->addWidget(mCloseButton);

  verticalLayout->addWidget(mTitlebarWidget);
  verticalLayout->addWidget(mMainWindow);

  QWidget *centralWidget = new QWidget(this);
  centralWidget->setObjectName("centralWidget");
  centralWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  centralWidget->setLayout(verticalLayout);

  setCentralWidget(centralWidget);
}
void BorderlessMainWindow::mousePressEvent(QMouseEvent* event) {
  if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
    return;

  if(event->button() == Qt::LeftButton) {
    mMoving = true;
    mLastMousePosition = event->pos();
  }
}
void BorderlessMainWindow::mouseMoveEvent(QMouseEvent* event) {
  if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
    return;

  if( event->buttons().testFlag(Qt::LeftButton) && mMoving) {
    this->move(this->pos() + (event->pos() - mLastMousePosition));
  }
}
void BorderlessMainWindow::mouseReleaseEvent(QMouseEvent* event) {
  if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
    return;

  if(event->button() == Qt::LeftButton) {
    mMoving = false;
  }
}
void BorderlessMainWindow::mouseDoubleClickEvent(QMouseEvent *event) {
  Q_UNUSED(event);
  if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
    return;

  mMaximized = !mMaximized;
  if (mMaximized) {
    slot_maximized();
  } else {
    slot_restored();
  }
}
void BorderlessMainWindow::slot_minimized() {
  setWindowState(Qt::WindowMinimized);
}
void BorderlessMainWindow::slot_restored() {
  mRestoreButton->setVisible(false);
  mMaximizeButton->setVisible(true);
  setWindowState(Qt::WindowNoState);
  setStyleSheet("#borderlessMainWindow{border:1px solid palette(highlight);}");
}
void BorderlessMainWindow::slot_maximized() {
  mRestoreButton->setVisible(true);
  mMaximizeButton->setVisible(false);
  setWindowState(Qt::WindowMaximized);
  setStyleSheet("#borderlessMainWindow{border:1px solid palette(base);}");
}
void BorderlessMainWindow::slot_closed() {
  close();
}

/*
MainWindow class: put all your code here
*/
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent, Qt::FramelessWindowHint), ui(new Ui::MainWindow) {
  ui->setupUi(this);
  statusBar()->setSizeGripEnabled(true);
}

MainWindow::~MainWindow() {
  delete ui;
}

Upvotes: 3

Ben Crowhurst
Ben Crowhurst

Reputation: 8491

Stumbled upon this seeking a resolution. Now sharing the solution in Qt 5.7

Qt::FramelessWindowHint

Produces a borderless window. The user cannot move or resize a borderless window via the window system. On X11, the result of the flag is dependent on the window manager and its ability to understand Motif and/or NETWM hints. Most existing modern window managers can handle this.

#include "mainwindow.h"
#include <QApplication>

int main( int argc, char *argv[] )
{
    QApplication app( argc, argv );

    MainWindow window;
    window.setWindowFlags( Qt::FramelessWindowHint );
    window.setParent( 0 );
    window.show( );

    return app.exec();
}

Upvotes: 2

Related Questions