QVideoWidget: Video is cut off - qt

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.

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

Restore geometry and state of an arbitrary QDialog

In our applications we are using customizable dialogs using exhaustively QSplitter, so that our customers can rearrange the dialogs to fit their needs.
(Sometimes we are also using QDockWidget, but this seems to be similar.)
Now, it is very annoying to rearrange the dialog every time it is opened again. Or even between different starts of the program.
After consulting the documentation I was able to restore the state and the geometry of a specific dialog containing one QSplitter.
#include <QApplication>
#include <QLabel>
#include <QDebug>
#include <QSplitter>
#include <QPushButton>
#include <QTextEdit>
#include <QDialog>
#include <QSettings>
#include <QHBoxLayout>
int main(int argc, char** args) {
QApplication app(argc, args);
app.setOrganizationName("Tech");
app.setOrganizationDomain("qt.us");
app.setApplicationName("RestoreLayout");
app.setApplicationVersion("1.0");
QDialog dialog;
dialog.setLayout(new QHBoxLayout);
auto splitter = new QSplitter;
splitter->addWidget(new QLabel("Left"));
splitter->addWidget(new QLabel("Right"));
dialog.layout()->addWidget(splitter);
auto accept = new QPushButton("Accept");
accept->connect(accept, &QPushButton::clicked, [&](){
dialog.accept();
});
splitter->addWidget(accept);
auto geom= QSettings().value("Geom").toByteArray();
auto splitterState = QSettings().value("State").toByteArray();
qDebug() << geom;
qDebug() << splitterState;
dialog.restoreGeometry(geom);
splitter->restoreState(splitterState);
dialog.show();
dialog.connect(&dialog, &QDialog::accepted, [&]() {
QSettings().setValue("Geom", dialog.saveGeometry());
QSettings().setValue("State", splitter->saveState());
app.quit();
});
app.exec();
}
Unfortunately, this seems to be an approach, which is not usable in general.
Assume, that there is some arbitrary dialog, that needs to restore its geometry and state. Even worser QSplitter and QDockWidget might be even used in a nested fashion, which is done in our applications.
How can an outside programmer restore the geometry and the state of a arbitrary dialog that might be easily applicable to all possible dialogs?
For saving states of QDockWidget each it must be named: dockWidgetN->setObjectName("dock-widget-N");
But you can save only QMainWindow state for saving states of docks in this window.
You can separatelly save states via QSettings (it's QByteArray) and use some one state for many windows.
See here: How to save state of a dialog in Qt?

How to play a video on a translucent QWidget?

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.

Qt MDI Area subwindow construction after show->() fails to update window size

I have a program that constructs a subwindow in a QT MDI Area, shows it, and later updates the contents of this window.
The program is large, but I have tried (and hopefully succeded) to reproduce the problem in the little program below.
In the middle of the program, there is the line commented "if this one is commented, then OK!".
As it says, if this line is commented, then the whole subwindow contents is created before Qt goes into the event loop and everything is fine...
BUT: is the line is there, then the contents of the MDI subwindow is constructed in 2 steps (as in my original program), but only the contents built in the first step shows up!
Run the little program below...
...if you now grab the sub-window (with the mouse), to move it, then Qt suddentely realize the size is wrong and updates the subwindow contents...
I could not figure out any way to get that correctly from start.
I am running Qt 4.8.0-7 on linux (Fedora).
#include <QApplication>
#include <QtCore>
#include <QMainWindow>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <stdlib.h>
QMdiArea* g1;
QGroupBox* g1a;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow* main_window = new(QMainWindow);
main_window->setObjectName("main_window");
main_window->resize(200, 200);
main_window->setWindowTitle("Hello");
g1 = new QMdiArea(main_window);
main_window->setCentralWidget(g1);
main_window->show();
g1a = new QGroupBox("G1A", g1);
QVBoxLayout *g1a_l = new QVBoxLayout(g1a);
g1a_l->addWidget(new QLabel("LABEL1"));
QMdiSubWindow *sub_window = new QMdiSubWindow(g1);
sub_window->setWidget(g1a);
sub_window->setAttribute(Qt::WA_DeleteOnClose);
app.processEvents(); //If this one is commented, then OK!
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label2"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label3"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label4"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label5"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label6"));
g1a_l->addWidget((QLabel*)new QLabel(" Nice Label7"));
sub_window->show(); //How to I get that to recaclulate the size of its contents?
return app.exec();
}
Thanks for helping!
Use adjustSize method:
sub_window->show(); // here or after adjustSize
sub_window->adjustSize();
It will adjust the size to fit sub_window contents (from documentation).

Resources