在Ubuntu的QT5中,如何将透明的QWidget放置在QMediaView的最上方?

11

目标

我希望我的基于QT5的GUI背景是一个正在播放的视频文件。同时,我还想能够使用透明度样式来装饰GUI组件,以便视频可以透过它们显示。

我不确定是否有可能实现这个目标。可能是因为我错过了重要线索(毕竟我是Qt新手),或者可能仅仅是因为它根本不可行。但作为一个乐观主义者,我已经尽力而为。

第一次尝试

我的最初尝试看起来像这样:

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();
}

按钮位于播放视频的顶部,这很好。但是如果你仔细看,你会发现按钮的角落里有一些黑色像素,表明它不是透明的,而是呈现为不透明的矩形。

First result screenshot

第二次尝试

我尝试使用background:transparent;样式来设置按钮(请参见上面代码中的注释行)。这使得按钮的背景变成了透明的,但是按钮后面的黑色框更加明显了。

enter image description here

其他尝试

我从网上阅读了几个来源的提示,尝试了很多方法都没有成功。我尝试使用QGraphicsScene和相关组件,在小部件中使用不同的布局堆栈和属性,以及许多其他尝试。我的最后一次尝试是将QVideoWidget的父级设置为QGLWidget()的实例,希望强制硬件加速可以解决我的问题(我的计算机具有二进制驱动程序的硬件3D加速)。这只是使窗口完全不出现了,但我仍然可以听到视频声音在背景中播放,表明应用程序仍在运行。

请求

我真的希望有一些善良而聪明的QT5开发者能够帮助我实现我的愿望,在Ubuntu上使用QT5在播放视频的情况下放置小部件。

谢谢!


我已经尝试了各种方法,但我认为这是不可行的 - 在我看来,这是QT 4.8的一个严重退步。不过,我已在您的问题上设置了悬赏,希望有人能给我们提供启示... - Mangled Deutz
我得出了同样的结论。自那时以来(我必须承认,有些不情愿),我已将我的应用程序的部分转换为QML/QtQuick 2.2来解决这个问题。这突然为我们打开了一个全新的灵活性和生产力的世界。不幸的是,这也使我们的应用程序取决于目标硬件上可用的GPU资源。这对我们自己带来了一些问题,但我们仍然很高兴进行了转换。谢谢您的赏金! - Mr. Developerdude
很遗憾,我不能使用QML(插入libvlc原因)。不过有趣的是它确实可以工作...最好的祝福。 - Mangled Deutz
3个回答

6

我知道这是一个老问题,你通过将应用程序的部分转换为QML/QtQuick 2.2来解决了你的问题,但我通过谷歌搜索遇到了同样的问题,其他人也可能会找到这个问题。我找到了一个解决方法,适用于在Windows上进行QT 5.3测试。

我的解决方法是使用QGraphicsView显示视频。这是我的代码(playerScreen是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);

我在playerScreen中禁用了滚动条,否则将会出现水平和垂直滚动条。

我有一个QWidget覆盖在playerScreen上,我使用QPainter在其中绘制。这个QWidget位于图形视图之上。

然后,当我播放视频时,我调用ui->playerScreen-show()。 我仅在播放时这样做,因为我还有另一个屏幕(与我的项目相关的其他内容),并且当使用/不使用视频时需要调用show / hide:)

如果您需要更多有关我的代码的信息,请告诉我。


谢谢,伙计!顺便说一下,在这里改进或添加旧问题是非常受欢迎的 :-) - Mr. Developerdude
不客气。如果你最终测试了它,请告诉我它的结果如何。 :) - Solidus
我会的。附:圣诞快乐。 - Mr. Developerdude
很高兴听到这个消息,Rigel! :) - Solidus

2
免责声明:本人未尝试过此解决方案。它适用于Qt 4.8,可在任何OpenGL渲染的内容上放置透明小部件。我只是假设媒体播放正在使用硬件加速。
黑色像素是Qt的后备缓冲区,在其中执行软件渲染。视频绕过此后备缓冲区,并且当“常规”qt小部件被绘制时,它会绘制在仍处于初始状态(黑色)的后备缓冲区上。
您可以将按钮(或包含按钮的小部件)作为单独的透明窗口。
setWindowFlags(Qt::FramelessWindowHint | Qt::SplashScreen);
setAttribute(Qt::WA_TranslucentBackground);

您需要手动定位它,以便它跟随您的窗口。

这意味着该按钮需要在窗口上安装一个事件过滤器,并监听任何移动或调整大小的事件。然后它会重新计算相对于窗口自己的位置,并更新它的位置。


在我看来,这应该被视为真正绝望的人(那些无法使用QtQuick的人)的hack。因此,在任何人能够实际确认它是否有效之前,我都不愿意接受它作为正确答案。实际上,这将把整个合成的责任转嫁给操作系统,这可能在某些情况下无法可靠地工作。 - Mr. Developerdude

-4

qwidget4.1

void setAutoFillBackground(bool enabled) //你有这个方法,试试看。

在论坛中搜索之前,始终要先尝试寻找答案,因为那里有很多答案。:) 不是我介意,而是因为这样更快。

一个具有完全透明背景的Qt小部件


你好!我认为你可能过于急躁了。你看,当我将按钮绘制在其他小部件上方时,它们是透明的。背景视频是罪魁祸首,由于视频显示区域的某些硬件加速。在发布我的问题之前,我已经非常努力地寻找解决方案,我也去了你建议的页面,但那些都不是答案。 - Mr. Developerdude
好的,我的错?我给了您需要的东西, http://qt-project.org/doc/qt-5.0/qtwidgets/qwidget.html您没有完全阅读文档。您可以传递一些渲染标志给qpushbutton,以获取父对象(如果没有指定)的背景。 或者使用自定义的qpushbutton并重新实现方法。感觉有点懒...暂时没有代码。 - adderly
你读了你提供的链接吗?引用:“左侧小部件没有设置其他属性或小部件属性。这种默认状态适用于大多数使用透明度的自定义小部件,不规则形状或不使用不透明画刷覆盖其整个区域。”我可以在我的代码中确认这一点,通过将最顶层的小部件移开视频并移到另一个小部件上,它看起来完全像应该的样子,没有黑色背景矩形,让背景透过来。我建议你自己试试 :) - Mr. Developerdude

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接