How to play a video on a translucent QWidget? - qt

I want to play a movie on a QWidget that has Qt::FramelessWindowHint flag and Qt::WA_TranslucentBackground attirbute using QVideoWidget or QGraphicsVideoItem. But the video is not visible. I hear only sound. What is the problem?
Edit:
#include "videoplayer.h"
#include <QtWidgets/QApplication>
#include "qboxlayout.h"
#include "qvideowidget.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *w = new QWidget;
w->setWindowFlags(Qt :: Window | Qt::FramelessWindowHint );
w->setAttribute(Qt::WA_TranslucentBackground, true);
w->setMinimumSize(300,200);
QVideoWidget *videoWidget = new QVideoWidget;
QBoxLayout *controlLayout = new QHBoxLayout;
controlLayout->setMargin(0);
controlLayout->addWidget(videoWidget);
w->setLayout(controlLayout);
QMediaPlayer mediaPlayer;
mediaPlayer.setVideoOutput(videoWidget);
mediaPlayer.setMedia(QUrl::fromLocalFile("C:/1.wmv"));
videoWidget->show();
mediaPlayer.play();
w->show();
return app.exec();
}

I solve the problem .when we set the WA_TranslucentBackground flag and FramelessWindowHint attribute the QVideoWidget's QPainter going to QPainter::CompositionMode_DestinationOver mode and it cause to nothing to show or a shadow on the screen . in this case i use a custom video widget and in paintEvent after createing QPainter painter(this); add
painter.setCompositionMode(QPainter::RasterOp_SourceAndNotDestination); or
painter.setCompositionMode(QPainter::RasterOp_SourceAndDestination);
to change the composition mode.

I've implemented VideoWidget some time ago. The only thing you shall change is your video path and set FramelessWindowHint flag.
You can find source here.

Related

How to make Transparent QT Dock Widget

On Windows ,I am trying to create Qt application with transparent DOCKWIDGETS, where background of dock widget is transparent when it is floated. So we can see through dock widget.
Currently it looks black as below.
Code as below
QDockWidget * dock3 = new QDockWidget(tr("DOCK3 TranslucentBackground"),
textEdit,Qt::FramelessWindowHint);
dock3->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
//dock3->setWindowFlags(dock2->windowFlags()|Qt::FramelessWindowHint);
dock3->setAttribute(Qt::WA_TranslucentBackground);
//dock3->setAttribute(Qt::WA_NoSystemBackground);
{
QWidget* WindowRect = new QWidget(dock3);
QWidget* titleRect = new QLabel ("Title",WindowRect);
titleRect->setFixedSize(QSize(30,60));
titleRect->setStyleSheet("background:rgb(0,0,255);");
QWidget* ContentRect = new QLabel("Content",WindowRect);
ContentRect->setFixedSize(QSize(60,30));
ContentRect->setStyleSheet("background:rgb(0,255,0);");
QVBoxLayout* layout = new QVBoxLayout(WindowRect);
layout->addWidget(titleRect);
layout->addWidget(ContentRect);
dock3->setWidget(WindowRect);
}
One way is to use setWindowOpacity(qreal) of the QDockWidget.
But keep in mind that this will apply the opacity to all children of the QDockWidget.
For reference: https://doc.qt.io/qt-5/qwidget.html#windowOpacity-prop
Another way is to use style sheets:
setStyleSheet("background-color: transparent;");. Unfortunately this doesn't work for top level widgets until you set the attribute WA_TranslucentBackground of the base widget.
For reference:
https://doc.qt.io/qt-5/stylesheet.html
https://doc.qt.io/qt-5/qwidget.html#styleSheet-prop
Try with this article:
Qt tip & Trick: Masking Widgets
You can do it with:
setStyleSheet("background-color: rgba(0,0,0,0)");
You can try to to it in the drawin customisation by changing the style of your widget like:
MyCustomWidget {background-color: none;}
It should work
I understand that you want to see through the docking bar only when it is floating. When it's not (docked), it makes no sense because there's nothing behind to be shown.
Using setAttribute(Qt::WA_TranslucentBackground) does the trick. I'm under Linux, hopefully, it also works for Windows (I found some posts where people additionally set setAttribute(Qt::WA_NoSystemBackground), it made no difference for me under Linux, if Qt::WA_TranslucentBackground is not enough for you, give it a try with both).
#include <QMainWindow>
#include <QApplication>
#include <QDockWidget>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
w.setCentralWidget( new QWidget() );
w.centralWidget()->setStyleSheet("background-color: green");
QDockWidget* dock = new QDockWidget();
dock->setWidget( new QLabel("Hello World",dock) );
// make docking bar transparent!
dock->setAttribute(Qt::WA_TranslucentBackground);
w.addDockWidget(Qt::BottomDockWidgetArea,dock, Qt::Horizontal);
w.show();
return a.exec();
}
When docked, it looks like this:
When floating, it looks like this:
You can see the central widget (green), can be visible through the docking bar.
Reference: Make QWidget transparent

Not mirroring layout direction in some of Qt widgets

I have an application which should have a right-to-left layout direction. But there some widgets(e.g. a QComboBox and a QlistWidget) which i don't want to mirror layout-direction (they should have left-to-right layout-direction whatever the layout-direction of app is).
What I'm looking for is something like LayoutMirroring.enabled in qml.
Is there a solution for this?
Edit:
This is a very simplified version of my code:
file widget.h:
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
file widget.cpp:
Widget::Widget(QWidget *parent): QWidget(parent){
setMinimumSize(300, 300);
QLabel *label1 = new QLabel("Right to left 1");
QLabel *label2 = new QLabel("Right to left 2");
QLabel *label3 = new QLabel("Right to left 3");
QComboBox *mCombo = new QComboBox();
mCombo->setMinimumWidth(150);
mCombo->addItems(QStringList({"Left to Right 1", "Left to Right 2", "Left to Right 3"}));
mCombo->setStyleSheet("QComboBox{padding: 0 10 0 10;}");
mCombo->setLayoutDirection(Qt::LeftToRight);
QVBoxLayout *mainlayout = new QVBoxLayout();
mainlayout->setAlignment(Qt::AlignLeft);
mainlayout->addWidget(mCombo);
mainlayout->addWidget(label1);
mainlayout->addWidget(label2);
mainlayout->addWidget(label3);
setLayout(mainlayout);}
and this my main.cpp:
#include "widget.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setLayoutDirection(Qt::RightToLeft);
Widget w;
w.show();
qDebug()<<a.layoutDirection() <<w.layoutDirection();
return a.exec();
}
comment: my project uses a stylesheet file and after playing with different parts of style for QComboBox I realized that the style "QComboBox{padding: 0 10 0 10;}" was causing the problem. So I included that, here. If I remove that line the problem will be solved.
note: I also realized that theWidget->setLayoutDirection(Qt::LeftToRight); will do what I was looking though I don't know it's the proper way or not!
So, The Problem was with the stylesheet that my app is using. this line of stylesheet "QComboBox{padding: 0 10 0 10;}" was the cause of problem. I removed it and problem solved. Though I don't know the reason.
Also for a specific widget that shouldn't get the app's layout-direction, the layout-direction must be set explicitly. like: theWidget->setLayoutDirection(Qt::LeftToRight);
And I realized it from Qt documentaion

QVideoWidget: Video is cut off

I want to play a video in a Qt Application. This is my code so far:
#include <QApplication>
#include <QWidget>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QUrl>
#include <iostream>
using namespace std;
const int WIDTH = 1280;
const int HEIGHT = 720;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
window.resize(WIDTH, HEIGHT);
window.setWindowTitle("Video Test");
window.show();
QMediaPlayer *player = new QMediaPlayer();
player->setMedia(QUrl::fromLocalFile("/Path/To/Video.mp4"));
QVideoWidget *videoWidget = new QVideoWidget(&window);
player->setVideoOutput(videoWidget);
videoWidget->resize(WIDTH, HEIGHT);
videoWidget->show();
player->play();
return app.exec();
}
The problem: The video is shown and plays back normally, but the video does not resize to fit in the QVideoWidget. The part of the video that is bigger than the widget is cut off.
Thanks in advance!
EDIT: I reduced the code and noticed, that when the application starts the video is cut off, but when I resize the window using the mouse it actually fits to the size:
#include <QApplication>
#include <QWidget>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QUrl>
#include <iostream>
using namespace std;
const int WIDTH = 1280;
const int HEIGHT = 720;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMediaPlayer *player = new QMediaPlayer();
QVideoWidget *videoWidget = new QVideoWidget();
player->setVideoOutput(videoWidget);
player->setMedia(QUrl::fromLocalFile("/Path/To/Video.mp4"));
player->play();
videoWidget->resize(WIDTH/3, HEIGHT/3);
videoWidget->show();
return app.exec();
}
For anyone in 2016, QVideoWidget is still busted. However, use a QGraphicsView widget, which holds a scene graph, and add a single QGraphicsVideoItem to the scene graph. Seems to work...
well, except that it's not exactly centered. and there's a 1px border on the left. and it hangs going into full screen most of the time. and I get errors like "updateVideoFrame called without AVPlayerLayer (which shouldn't happen". Progress!
.. oh, and it takes up about 10x the cpu too.
You know what does work, and works great? GStreamer. Thank you, gstreamer. Even integrating it in python/qt works fabulously.
I ran into a similar problem in PyQt5. I worked around it by setting the geometry of the QVideoWidget to its current geometry before playing the video. I am guessing something in the resizeEvent signal must handle the scaling of the media and isn't triggered when initialized.
After many hours of looking for the error, I think this is a bug in Qt on OSX, as I watched this YouTube video https://www.youtube.com/watch?v=tGKmQy-VBX0 and tried out the code.
In the video scaling works fine, but on my machine not.
After playing, I resized the QVideoWidget by 1 and then resized to original size.
Definitely "fudge", but this works for me until I find a real solution:
(working with PyQt5 and High Sierra)
s1 = self.MediaFrame.size() # QVideoWidget
s2 = s1 + QSize(1, 1)
self.MediaPlayer.play() # QMediaPlayer
self.MediaFrame.resize(s2) # enlarge by one pixel
self.MediaFrame.resize(s1) # return to original size
Usually the scale mode dictates how the video fills the widget.
The scale mode FitInView will force the video to fill the view keeping aspect ratio.
However, this scale mode should be the default. You can try to set it manually:
QVideoWidget *videoWidget = new QVideoWidget(&window);
videoWidget->setScaleMode(Phonon::VideoWidget::FitInView);
player->setVideoOutput(videoWidget);
If you still searching for a solution to this, QVideoWidget class has setAspectRatioMode method. Use this to scale frames of video to fit your widget area.

Qt: QMenu with translucent background

I use Windows and I want to set a style sheet to a QMenu to give it a translucent background. In order for that to work, I first set the FramelessWindowHint, then I set the WA_TranslucentBackground attribute. Then I set my style sheet and display the menu with the popup method. It is drawn correctly, but it behaves strangely: As soon as it has the FramelessWindowHint, it is always visible (even before calling the popup() method). It does not hide itself anymore after one of its entries has been clicked.
Here is a minimalistic example:
#include <QApplication>
#include <QMenu>
#include <QPoint>
#include <QCursor>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMenu menu;
menu.addAction("about", &a, SLOT(aboutQt()));
menu.addAction("exit", &a, SLOT(quit()));
menu.setWindowFlags(Qt::FramelessWindowHint);
menu.setAttribute(Qt::WA_TranslucentBackground);
menu.setStyleSheet("QMenu{background:rgba(255, 0, 0, 50%);}");
menu.popup(QCursor::pos());
return a.exec();
}
menu.setWindowFlags(menu.windowFlags() | Qt::FramelessWindowHint);
should solve your problem. Now you are clearing all flags already set by Qt.

QLabel consuming too much space

I use a QLabel and QPLineEdit within a QStackedWidget , the QLable should be nearly the size of the window holding this widget.
But when I set a extra long text to QLabel , it's expanding too much , and I'm not able to reduce the window size horizontally , the minimum width was too much.
I set the size policy of these three widgets to Minimum already , it just won't work for me.
UPDATE
maybe it's better saying like this: how to let QLabel display part of the text , when there's not enough space
SAMPLE CODE
#include <QtGui>
int main ( int argc , char **argv )
{
QApplication app (argc , argv);
QWidget w;
QLabel *label = new QLabel ("Very very very long text");
label->setSizePolicy (QSizePolicy::Minimum , QSizePolicy::Fixed);
QVBoxLayout layout (&w);
layout.addWidget ( label );
w.show();
return app.exec();
}
If I understand you correctly, the simplest thing to do is simply to ignore that label's horizontal size hint.
As long as you have other widgets in there (or force a minimum width manually to the container), this should do what you want:
#include <QtGui>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QLabel *l1 = new QLabel("This very long text doesn't influence "
"the width of the parent widget");
l1->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
// Style just to make it clear that the widget is
// being resized to fit the parent, it doesn't "overflow"
l1->setFrameShape(QFrame::Box);
l1->setFrameShadow(QFrame::Raised);
l1->setAlignment(Qt::AlignHCenter);
QLabel *l2 = new QLabel("This influences the width");
l2->setFrameShape(QFrame::Box);
l2->setFrameShadow(QFrame::Raised);
QWidget w;
QVBoxLayout layout(&w);
layout.addWidget(l1);
layout.addWidget(l2);
w.show();
return app.exec();
}

Resources