Reputation: 39
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
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 ®ion);
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 ®ion)
{
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
Reputation: 7150
Just setting the color
of the Window
to transparent
and set flags: Qt.FramelessWindowHint
works for me on macOS :
Upvotes: 1
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