Create a drawer in QWidget application

I want to have some kind of drawer in my program (not exactly a drawer that for example we see in android app, I want icon of button inside of the to be visible when the drawer is close, I attached some draft of what Im after) In close mode In open mode noticed how the background getting darker when the drawer opened? I want a drawer that can open as an overlay to the main program page, and when its open put a shadow in all widget behind it...

I can simply create a QWidget and put it in a grid layout beside the main widget that going to hold all other pages, but problem with that is, if I try to open it (with QPropertyAnimation and changing size of it of course) it will just expand in same layer of the main widget, so it will shrink other widget down in order to expand... And this is not good

so Im thinking is it possible with QWidget?

I will attach an example that do what im looking for but in the wrong way that I said before at end of question

/--- example ---/
mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>783</width>
    <height>525</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="minimumSize">
   <size>
    <width>783</width>
    <height>525</height>
   </size>
  </property>
  <property name="maximumSize">
   <size>
    <width>783</width>
    <height>525</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QFrame" name="sideMenu">
      <property name="minimumSize">
       <size>
        <width>70</width>
        <height>0</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>70</width>
        <height>16777215</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: rgb(83, 86, 94);
border-radius:8;</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <layout class="QFormLayout" name="formLayout">
       <item row="0" column="0">
        <widget class="QPushButton" name="menuButton">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="minimumSize">
          <size>
           <width>51</width>
           <height>51</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
           <width>51</width>
           <height>51</height>
          </size>
         </property>
         <property name="styleSheet">
          <string notr="true">QPushButton { background-color: rgb(197, 255, 134); }
QPushButton:hover { background-color: rgb(172, 222, 117); }
QPushButton:pressed { background-color: rgb(87, 112, 59); }</string>
         </property>
         <property name="text">
          <string>OPEN</string>
         </property>
        </widget>
       </item>
       <item row="1" column="0">
        <spacer name="verticalSpacer">
         <property name="orientation">
          <enum>Qt::Vertical</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>20</width>
           <height>40</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QFrame" name="ppage">
      <property name="minimumSize">
       <size>
        <width>689</width>
        <height>507</height>
       </size>
      </property>
      <property name="maximumSize">
       <size>
        <width>689</width>
        <height>507</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));
border-radius:8;</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPropertyAnimation>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void toggle_animation();

private:
    Ui::MainWindow *ui;
    QPropertyAnimation *animation;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    animation = new QPropertyAnimation(ui->sideMenu, "minimumWidth");

    QObject::connect(ui->menuButton, &QPushButton::released, this, &MainWindow::toggle_animation);
}

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

void MainWindow::toggle_animation()
{
    animation->stop();
    if (ui->sideMenu->width() == 70)
    {
        animation->setStartValue(ui->sideMenu->width());
        animation->setEndValue(250);
        ui->menuButton->setText("Close");
    }
    else
    {
        animation->setStartValue(ui->sideMenu->width());
        animation->setEndValue(70);
        ui->menuButton->setText("Open");
    }
    animation->setEasingCurve(QEasingCurve::InOutCubic);
    animation->setDuration(470);
    animation->start();
}

While I think this kind of fancy UI would be easier to write in QML, it should definitely be possible with QWidgets. After playing around with some properties in Qt Designer, I think the following will at least make the drawer work as intended.

mainwindow.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>783</width>
    <height>525</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="minimumSize">
   <size>
    <width>783</width>
    <height>525</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <property name="sizePolicy">
    <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
     <horstretch>0</horstretch>
     <verstretch>0</verstretch>
    </sizepolicy>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QFrame" name="sideMenu">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="minimumSize">
       <size>
        <width>70</width>
        <height>0</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: rgb(83, 86, 94);
                                border-radius:8;</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <layout class="QFormLayout" name="formLayout">
       <item row="0" column="0">
        <widget class="QPushButton" name="menuButton">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="minimumSize">
          <size>
           <width>51</width>
           <height>51</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
           <width>51</width>
           <height>51</height>
          </size>
         </property>
         <property name="styleSheet">
          <string notr="true">QPushButton { background-color: rgb(197, 255, 134); }
                                            QPushButton:hover { background-color: rgb(172, 222, 117); }
                                            QPushButton:pressed { background-color: rgb(87, 112, 59); }</string>
         </property>
         <property name="text">
          <string>OPEN</string>
         </property>
        </widget>
       </item>
       <item row="1" column="0">
        <spacer name="verticalSpacer">
         <property name="orientation">
          <enum>Qt::Vertical</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>20</width>
           <height>40</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item>
     <widget class="QFrame" name="ppage">
      <property name="sizePolicy">
       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="minimumSize">
       <size>
        <width>689</width>
        <height>507</height>
       </size>
      </property>
      <property name="autoFillBackground">
       <bool>false</bool>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));
                                border-radius:8;</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_2"/>
     </widget>
    </item>
   </layout>
   <zorder>ppage</zorder>
   <zorder>sideMenu</zorder>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

The changes here are:

  • MainWindow starts at a minimum size, but can be made larger;
  • The ppage widget expands horizontally and vertically, while the sideMenu only expands vertically.

The menu will also expand to cover the page if you animate its size like this:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    animation = new QPropertyAnimation(ui->sideMenu, "size"); 
    animation->setEasingCurve(QEasingCurve::InOutCubic);
    animation->setDuration(470);

    QObject::connect(ui->menuButton, &QPushButton::released, this, &MainWindow::toggle_animation);
}

void MainWindow::toggle_animation()
{ 
    animation->stop();
    auto const current = ui->sideMenu->size();
    animation->setStartValue(current);
    if (current.width() == 70)
    {
        animation->setEndValue(QSize(250, current.height()));
        ui->menuButton->setText("Close");
    }
    else
    {
        animation->setEndValue(QSize(70, current.height()));
        ui->menuButton->setText("Open");
    }
    animation->start();
}

However, this introduces the possibility of resizing the window while the side menu is opened, which bypasses the animation code and makes it snap back unceremoniously to its original width. Fixing this would probably require a different solution, because widgets aren't normally made to overlap and it doesn't play well with layouts. Maybe something like a Dialog would work better.

As for the shaded effect, I'm not sure what the best solution would be, but this answer has some example code that should work.