Mathias
Mathias

Reputation: 39

Qt non rectangular window

I am trying to create a non rectangular window with Qt.

Like this:

           ______________________
          |                      |
    ______|                      |
  /                              |
 /                               |
|                                |
|                                |
 \                               |
  \_______                       |
          |                      |
          |                      |
          |                      |
          |______________________|

With the transparent parts actually being click through to the non-Qt window below.

The only way I have found to get this done is: window->setMask(complex_region);

But that seems pretty hacky, especially since I now need to know the sizes of window parts both in the C++ and qml.

Ideally I would like to tell Qt to just not render fully transparent stuff.

Upvotes: 0

Views: 1406

Answers (3)

derM
derM

Reputation: 13691

If your main concern is, that you want to set the mask from QML, you can create a QObject that is accessible from QML to tunnel to the methods setMask and mask of the QWindow.

I have decided I will create this Object from within QML. The design might be improved, but it works, and shall outline the idea.

exposemask.h

#ifndef EXPOSEMASK_H
#define EXPOSEMASK_H

#include <QObject>
#include <QRegion>
#include <QWindow>

class ExposeMask : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QRegion mask READ mask WRITE setMask)

public:
    ExposeMask(QObject* parent = nullptr);

    Q_INVOKABLE void setWindow(QWindow* win);
    // Little helper to get a region from a image in QML.
    Q_INVOKABLE QRegion regionFromImage(QString path);

    QRegion mask() const;

    void setMask(const QRegion &region);

private:
    QWindow* m_window;

};

#endif // EXPOSEMASK_H

exposemask.cpp

#include "exposemask.h"
#include <QPixmap>
#include <QBitmap>
#include <QDebug>

ExposeMask::ExposeMask(QObject* parent)
        : QObject(parent)
        , m_window(nullptr)
{
}

QRegion ExposeMask::regionFromImage(QString path)
{
        QPixmap pix(path);
        return pix.mask();
}

QRegion ExposeMask::mask() const
{
    if (m_window != nullptr)
    {
        return m_window->mask();
    }
    else
    {
        qDebug() << "No Window Set";
    }
}

void ExposeMask::setMask(const QRegion &region)
{
    m_window->setMask(region);
}

void ExposeMask::setWindow(QWindow* win) { m_window = win; }

In main.cpp -> int main([...])

qmlRegisterType<ExposeMask>("ExposeMask", 1, 0, "ExposeMask");

In main.qml

ExposeMask {
    // I need to do it "onCompleted" for I need to set the window first...
    // You can change this by having the region as a member, exposing the window as property e.t.c
    Component.onCompleted: {
        setWindow(appwindow)
        mask = regionFromImage("mask.png")
    }
}

For handling the shapes it might be easier, if you have multiple windows with the right shape. So in the case of your drawing I would use two windows, where one is rectangular, and only the protuberance needs to be masked. So individual changes of their sizes are easier to calculate.

Also, if the calculations become complex, consider adding well suited helper functions to the exposed object in C++

Upvotes: 0

GrecKo
GrecKo

Reputation: 7150

Just setting the color of the Window to transparent and set flags: Qt.FramelessWindowHint works for me on macOS :

non rectangular qml window

Upvotes: 1

doudouremi
doudouremi

Reputation: 186

You can create a main widget and with qpainter you draw the design. After all others widgets are inside the main widget. Finally, you add transparancy for the main widget and you have what you want.

Upvotes: 1

Related Questions