Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

First result screenshot

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.

enter image description here

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!

like image 745
Lennart Rolland Avatar asked Jun 03 '13 02:06

Lennart Rolland


2 Answers

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.

like image 193
Solidus Avatar answered Sep 21 '22 17:09

Solidus


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.

like image 30
Bgie Avatar answered Sep 20 '22 17:09

Bgie