Soroush Rabiei
Soroush Rabiei

Reputation: 10878

Make QWidget transparent

I have a QWidget-based overlay widget which should paint some text and take place over the central widget of my application. The problem is that I can't set background of overlay widget to be transparent. What I already tried:

  1. setPalette(Qt::transparent);
  2. setAttribute( Qt::WA_TranslucentBackground, true );
  3. setAttribute( Qt::WA_OpaquePaintEvent, true );
  4. setAutoFillBackground(false);
  5. setStyleSheet("QWidget{background-color: transparent;}");
  6. setAttribute(Qt::WA_NoSystemBackground);

Upvotes: 27

Views: 49620

Answers (4)

Kitiara
Kitiara

Reputation: 498

Here it is how you create a transparent QWidget. The important thing is if you remove Qt::FramelessWindowHint then the transparency removes the contents inside. So if you want the title bar too, then you need to create a custom title bar, there is no workaround. Or you could use QML which supports transparency with the standard title bar.

#include <QApplication>
#include <QLabel>
#include <QPainter>

class PaintEventFilter : public QObject {
protected:
    bool eventFilter(QObject* obj, QEvent* event) override {
        if (event->type() == QEvent::Paint) {
            QWidget* widget = qobject_cast<QWidget*>(obj);
            if (widget) {
                QPainter painter(widget);

                painter.setBrush(QBrush(QColor(0, 0, 255, 128)));
                painter.drawRect(50, 100, 200, 100);

                painter.setPen(Qt::white);
                painter.drawText(widget->rect(), Qt::AlignCenter, "Transparent Window Test");
            }
            return true;
        }
        return QObject::eventFilter(obj, event);
    }
};

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

    QWidget* wid = new QWidget();
    wid->setWindowTitle("test");
    wid->setGeometry({ 0,0,300,300 });
    wid->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); // If you remove Qt::FramelessWindowHint, the transparency will remove the content inside!
    wid->setAttribute(Qt::WA_TranslucentBackground);
    QLabel* label = new QLabel("This is a transparent window", wid);
    label->setStyleSheet("QLabel { color : white; font-size: 16px; }");
    label->setGeometry(50, 50, 200, 50);

    // Install the event filter
    PaintEventFilter* filter = new PaintEventFilter();
    wid->installEventFilter(filter);
    wid->show();

    return app.exec();
}

Upvotes: 1

Slawek Rewaj
Slawek Rewaj

Reputation: 819

The best solution is provided by Gökmen Göksel in one of the comments of this article

setStyleSheet("background-color: rgba(0,0,0,0)");

Upvotes: 16

UndeadDragon
UndeadDragon

Reputation: 707

On Linux works with:

setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);

Upvotes: 16

Antonio Dias
Antonio Dias

Reputation: 2881

My best guess to show an overlay widget, is convert the widget to a window, resize it to it's contents and move them to the desired position manually.

MainWindow Example, showing the overlay widget in the center of the video widget:

Mwindow::Mwindow()
{
    widget = new Widget(this);
}

void Mwindow::widgetSizeMove()
{
    if (widget->width() <= videoWidget->width() && widget->height() <= videoWidget->height())
    {
        widget->setWindowOpacity(1); // Show the widget
        QPoint p = videoWidget->mapToGlobal(videoWidget->pos());
        int x = p.x() + (videoWidget->width() - widget->width()) / 2;
        int y = p.y() + (videoWidget->height() - widget->height()) / 2;
        widget->move(x, y);
        widget->raise();
    }
    else
    {
        widget->setWindowOpacity(0); // Hide the widget
    }
}

bool Mwindow::event(QEvent *event)
{
    switch (event->type())
    {
    case QEvent::Show:
        widget->show();
        QTimer::singleShot(50, this, SLOT(widgetSizeMove())); 
        //Wait until the Main Window be shown
        break;
    case QEvent::WindowActivate:
    case QEvent::Resize:
    case QEvent::Move:
        widgetSizeMove();
        break;
    default:
        break;
    }

    return QMainWindow::event(event);
}

Widget Example:

Widget::Widget(QWidget *parent) : QWidget(parent)
{
    setWindowFlags(Qt::Window | Qt::FramelessWindowHint);

    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_TranslucentBackground);
    setAttribute(Qt::WA_PaintOnScreen);

    setAttribute(Qt::WA_TransparentForMouseEvents);
}

void Widget::paintEvent(QPaintEvent*)
{
    QPainter p(this);
    QString text = "Some foo goes here";
    QFontMetrics metrics(p.font());
    resize(metrics.size(0, text));
    p.drawText(rect(), Qt::AlignCenter, text);
}

Example when showing a video with LibVLC:

VLC based player

Upvotes: 26

Related Questions