简体   繁体   中英

Put transparent QWidget on top of QMediaView in QT5 on Ubuntu

Goal

I want the background of my QT5 based GUI to be a video file that is playing. I also want to be able to style my GUI components with transparency so that the video will show through them.

I am not sure if this is at all possible to accomplish. It could be that i've just missed an important clue (I am after all a Qt beginner), or it could be that it just simply was not meant to work. But being an optimist, I have given it my best try.

First attempt

My minimal first attempt looked like this:

int main( int argc, char **argv ){
    QApplication app(argc, argv);
    QMediaPlayer *media=new QMediaPlayer(0);
    QVideoWidget *video=new QVideoWidget(0); //new QGLWidget()
    media->setVideoOutput(video);
    media->setMedia(QUrl::fromLocalFile("/tmp/avatar.mp4"));
    media->setPosition(3000000);
    media->play();
    QPushButton *pb=new QPushButton(video);
    pb->setText(QString("BOB"));
    //pb->setStyleSheet(QString("background:transparent;"));
    video->show();
    return app.exec();
}

The button is on top of the playing video, which is good. But if you look closely, you will see some black pixels in the corners of the button indicating that it is not transparent over the video, but rendered as an opaque rectangle.

第一个结果截图

Second attempt

I tried styling the button with background:transparent; (see commented line in code above). This made the background of the button transparent, but the black box behind the button is now even more evident.

在此输入图像描述

Other attempts

I have read several tips from various sources on-line on how to do this. None have worked for me. I have tried working with QGraphicsScene and friends, different stacks of layouts, different attributes on the widgets in question and many more. My last attempt was to set the parent of the QVideoWidget to an instance of QGLWidget() in the hope that forced hardware acceleration would solve my problems (my computer has hardware 3d acceleration with binary driver). This simply stopped the window from appearing at all, while I could still hear the soundtrack of the video playing in the background indicating that the application was still running.

Request

I really hope that there are some kindhearted and smart QT5 developers out there that can help me fulfill my dream of having widgets placed atop of a playing video in QT5 on Ubuntu.

Thank you!

I know this is an old question and you managed to solve your problem by converting parts of your application to QML/QtQuick 2.2 but I ended up bumping into it by google search and someone else with the same problem might also find this. I found a solution that worked for me and has been tested on Windows with QT 5.3.

What I did was use a QGraphicsView to display the video. Here's my code (playerScreen is the QGraphicsView):

QGraphicsVideoItem *item = new QGraphicsVideoItem;
item->setSize(ui->playerScreen->size());
player.reset(new QMediaPlayer());
player->setVideoOutput(item);
QGraphicsScene *scene = new QGraphicsScene(0, 0, ui->playerScreen->size().width(), ui->playerScreen->size().height());
ui->playerScreen->setScene(scene);
ui->playerScreen->scene()->addItem(item);

I disabled the scroll bars on playerScreen otherwise there would be horizontal and vertical scrollbars.

I have a QWidget on top of the playerScreen in which I draw with QPainter. That QWidget is on top of the graphics view.

Then, when I play the video, I call ui->playerScreen-show() . I do this only on play because I have another screen on top (for another stuff related to my project) and I need to call show/hide when the video is being used/not used :)

Let me know if you need more information on my code.

Disclaimer: I have not tried this solution. It works on Qt 4.8 to put transparant widgets over anything that is OpenGL rendered. I am just assuming the media play is using hardware acceleration.

The black pixels are Qt's backbuffer where software rendering is performed. The video bypasses this backbuffer, and when a 'regular' qt widget is drawn, it draws on top of the backbuffer which is still in it's initial state (black).

You could make the button (or a widget containing the button) a separate, transparant window.

setWindowFlags(Qt::FramelessWindowHint | Qt::SplashScreen);
setAttribute(Qt::WA_TranslucentBackground);

You would need to position it manually though, so it follows your window. This means the button needs to install an eventfilter on the window, and listen to any move or resize events. It then recalculates its own position, relative to the window, and updates it position.

qwidget4.1

void setAutoFillBackground(bool enabled) //you have that method, try it.

Always search in the forum before, cause there are a lot of answers. :) not that i mind, its faster for you.

A qt widget with fully transparent background

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM