qt: How to animate the transparency of a QDeclarativeView using QPropertyAnimation? - qt

I want to use QPropertyAnimation to animate the transparency of a QDeclarativeView .But,it doesn't work.It's nothing to change and no errors, but I use property "geometry",it works.I have no ideas.
Here is my main.cpp code:
int main(int argc, char *argv[])
{
QApplication a(argc, argv, true);
QDeclarativeView* view;
QDeclarativeContext *context;
QDeclarativeEngine* engine;
Connector* connector;
view = new QDeclarativeView();
connector = new Connector();
context = view->rootContext();
context->setContextProperty("Connector", connector);
context->setContextProperty("gRadioQMLDir", QDir::currentPath());
view->setSource(QUrl::fromLocalFile("qml/Main.qml"));
view->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
view->show();
QPropertyAnimation animation(view, "windowOpacity");
animation.setDuration(30000);
animation.setStartValue(0.0);
animation.setEndValue(1.0);
animation.start();
return a.exec();
}

Try to animate widget with using QGraphicsOpacityEffect. Sample:
#include <QApplication>
#include <QWidget>
#include <QDeclarativeView>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QPushButton>
int main( int argc, char *argv[] )
{
QApplication a( argc, argv );
QWidget w;
QGraphicsOpacityEffect *opacity = new QGraphicsOpacityEffect;
QPropertyAnimation *anim = new QPropertyAnimation( opacity, "opacity" );
//QDeclarativeView *dv = new QDeclarativeView( &w );
//dv->setFixedSize( 200, 200 );
//dv->setGraphicsEffect( opacity );
QPushButton *btn = new QPushButton( "Button", &w );
btn->setGraphicsEffect( opacity );
anim->setDuration( 2000 );
anim->setStartValue( 0.1 );
anim->setEndValue( 1.0 );
anim->setEasingCurve( QEasingCurve::InCubic );
anim->start();
w.setFixedSize( 300, 200 );
w.show();
return a.exec();
}
Note: "windowOpacity" property is valid only for widgets that are windows.

Related

Qt QChart background not updated

I am using Qt5.9.6 and when changing QChart axis ranges background is not updated. As soon as other application is chosen to be active background is updated.
after range change
Any idea ? Thanks
I tried to create a representative example of my application but the example (unfortunately) works.
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QScatterSeries>
#include <QtCharts/QChart>
#include <QtCharts/QValueAxis>
#include <QDebug>
#include <qslider>
#include <QLayout>
#include <qwidget>
#include <QtMath>
#include <QApplication>
QT_CHARTS_USE_NAMESPACE
int main(int argc, char *argv[])
{
QApplication a {argc, argv};
struct {
const double nbr_of_per {5.5};
// number of samples
const int nos {(int)(nbr_of_per*200*M_PI)};
} sine_params;
const int sld_max {sine_params.nos-1};
const double div {100.0};
QSlider * sld {new QSlider{Qt::Horizontal}};
QChartView * view {new QtCharts::QChartView{}};
QChart * chart {new QtCharts::QChart{}};
QLineSeries sine {};
QScatterSeries point {};
sld->setRange(0, sld_max);
chart->addSeries(&sine);
chart->addSeries(&point);
// for(auto e: chart->series())
// e->setUseOpenGL(true);
for(double i{}; i< sine_params.nos;i++)
sine.append(QPointF{i/div, sin(i/div)});
point.append(QPointF{});
point.setMarkerSize(20);
chart->legend()->hide();
QValueAxis x_ax;
x_ax.setRange(0, sine.pointsVector().last().x());
x_ax.setTickCount(5);
x_ax.setLabelFormat(QString{"%."+QString::number((int)log10(div))+"f"});
chart->setAxisX(&x_ax, &sine);
chart->setAxisX(&x_ax, &point);
QValueAxis y_ax;
y_ax.setRange(-1, 1);
y_ax.setTickCount(5);
y_ax.setLabelFormat("%.3f");
chart->setAxisY(&y_ax, &sine);
chart->setAxisY(&y_ax, &point);
QFont font{chart->axisX()->labelsFont()};
font.setPixelSize(20);
chart->axisX()->setLabelsFont(font);
chart->axisY()->setLabelsFont(font);
view->setChart(chart);
view->setRenderHint(QPainter::Antialiasing);
QVBoxLayout * vl{new QVBoxLayout};
vl->addWidget(view);
vl->addWidget(sld);
QWidget w;
w.setLayout(vl);
w.show();
QObject::connect(sld, &QSlider::valueChanged,
[=,&sine,&point](int val){
QPointF p{val/div, sine.at(val).y()};
point.clear();
point.append(p);
chart->axisX()->setRange(p.x()-(100/div), p.x()+(100/div));
chart->axisY()->setRange(p.y()-(.1), p.y()+.1);
// in my misbehaving application i have to use update() and only
// then I do not get 'leftovers' after changing axis ranges
// view->scene()->update(view->rect());
}
);
return a.exec();
}
very annoying

How to avoid crash in QQuickView?

Are there any ways to correclty close QQuickView without crashes? I posted a bug to Digia, but there still no response :(
QML:
import QtQuick 2.2
import QtQuick.Controls 1.2
Rectangle
{
id: root;
signal quit();
Component.onDestruction: quit();
BusyIndicator
{
id: progress
running: true
anchors.fill: parent
}
}
CPP:
#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
#include <QPointer>
int main(int argc, char *argv[] )
{
QGuiApplication a( argc, argv );
QPointer< QQuickView > w = new QQuickView();
QObject::connect( w, &QQuickView::statusChanged, [=]()
{
QObject::connect( w->rootObject(), SIGNAL( quit() ), qApp, SLOT( quit() ) );
} );
w->setSource( QUrl( "qrc:/test.qml" ) );
w->setResizeMode( QQuickView::SizeRootObjectToView );
w->show();
a.exec();
return 0;
}

Deleting QQuickView on exit cause Qt application to freeze

I founded a deadlock in Qt 5.3. How to fix in correctly? Without ugly fix (not to delete qquickview *)
I have a singleton with a pointer to QQuickView. When I need to close my application I do a call of QGuiApplication::quit() and try to release QQuickView * in destructor of singlenot. Result - application freezes.
Sample:
test.qml
import QtQuick 2.1
Rectangle
{
id: root;
color: "black";
signal quit();
Component.onDestruction: quit();
}
main.cpp
#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
#include <QPointer>
struct Singleton
{
QPointer< QQuickView > w;
static Singleton inst;
int run( int argc, char *argv[] )
{
QGuiApplication a( argc, argv );
w = new QQuickView();
QObject::connect( w, &QQuickView::statusChanged, [=]()
{
QObject::connect( w->rootObject(), SIGNAL( quit() ), qApp, SLOT( quit() ) );
} );
w->setSource( QUrl( "qrc:/test.qml" ) );
w->setResizeMode( QQuickView::SizeRootObjectToView );
w->show();
a.exec();
return 0;
}
~Singleton()
{
delete w; // Comment this to fix bug
}
};
Singleton Singleton::inst;
int main(int argc, char *argv[] )
{
Singleton::inst.run( argc, argv );
return 0;
}
P.S. C++0x is used for simplifying code. Same result on C++03 compilers.
It was a bug in Qt. Fixed since 5.4 version.

Capture QML drawing buffer, without displaying

I need to grab each QML (QtQuick 2) drawing frame and sent it over the network.
At the moment I have used method listed below, but this method has two big disadvantage
1) Due to Qt5 documentation grabWindow() function has performance issues
2) It can't work with hidden QML window
Is it possible to get OpenGL render buffer right after QQuickWindow::afterRendering ?
Using FBOs ? Shared opengl context ?
class Grab: public QObject
{
public:
Grab( QQuickWindow * wnd ) : wnd_(wnd) {}
public slots:
void Grabme()
{
QImage image = wnd_->grabWindow();
}
private:
QQuickWindow *wnd_;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/grab1/main.qml"));
viewer.showExpanded();
Grab grab( &viewer );
QObject::connect( &viewer, &QtQuick2ApplicationViewer::frameSwapped,
&grab, &Grab::Grabme, Qt::DirectConnection );
return app.exec();
}
Example bellow can grab any qml content to FBO and then sent it as Image via signal.
Only one problem of this approach is visibility, grab window must be visible for successful grabbing. If anybody knows how to prevent this you can help me and provide more advanced approach.
// main.cpp
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
GrabWindow grab;
grab.setResizeMode( QQuickView::SizeViewToRootObject );
grab.setSource( QUrl::fromLocalFile("qml/main.qml") );
grab.setFlags( Qt::Popup );
grab.show();
return app.exec();
}
// grabwindow.hpp
#pragma once
#include <QOpenGLFramebufferObject>
#include <QScopedPointer>
#include <QQuickView>
#include <QImage>
class GrabWindow: public QQuickView
{
Q_OBJECT
signals:
void changeImage( const QImage &image );
public:
GrabWindow( QWindow * parent = 0 );
private slots:
void afterRendering();
void beforeRendering();
private:
QScopedPointer<QOpenGLFramebufferObject> fbo_;
};
// grabwindow.cpp
#include "grabwindow.hpp"
#include <limits>
GrabWindow::GrabWindow( QWindow * parent ) :
QQuickView( parent )
{
setClearBeforeRendering( false );
setPosition( std::numeric_limits<unsigned short>::max(), std::numeric_limits<unsigned short>::max() );
connect( this, SIGNAL( afterRendering() ), SLOT( afterRendering() ), Qt::DirectConnection );
connect( this, SIGNAL( beforeRendering() ), SLOT( beforeRendering() ), Qt::DirectConnection );
}
void GrabWindow::afterRendering()
{
if( !fbo_.isNull() )
{
emit changeImage( fbo_->toImage() );
}
}
void GrabWindow::beforeRendering()
{
if (!fbo_)
{
fbo_.reset(new QOpenGLFramebufferObject( size(), QOpenGLFramebufferObject::NoAttachment) );
setRenderTarget(fbo_.data());
}
}
I managed to find a trick to make grabWindow() work when the Window is "not visible". The trick is to set the window's visibility: Window.Minimized and the flags: Qt.Tool. The window is not displayed to the user, but to the Qt's internals it appears to be visible and the grabWindow() method call works as expected. Remember to call that method only once the scene has been initialised.
The only problem with this solution (that I have come across) is that if the window's color property is set to transparent, the captured content has black background.
With later versions of Qt 5.X you can also use the software render backend.
The following renders any scene in the background without any visible window or OpenGL tricks:
// main.cpp
#include <QGuiApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQuickItem>
#include <QQuickWindow>
#include <QQuickRenderControl>
int main(int argc, char *argv[])
{
const char *source = "qrc:/main.qml";
if (argc > 1) source = argv[1];
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
QGuiApplication app{argc, argv};
QQuickRenderControl renderControl;
QQuickWindow window{&renderControl};
QQmlEngine engine;
QQmlComponent component{
&engine,
QUrl{QString::fromUtf8(source)}
};
QQuickItem *rootItem = qobject_cast<QQuickItem *>(component.create());
window.contentItem()->setSize(rootItem->size());
rootItem->setParentItem(window.contentItem());
window.resize(rootItem->size().width(), rootItem->size().height());
QImage image = renderControl.grab();
image.save("output.png");
return 0;
}

Why doesn't setPos() move the QGraphicsItems in the scene?

In the code below, I have three QGraphicsItems that are laid out by QGraphicsLinearLayout, which is set as layout to a QGraphicsWidget.
#include <QApplication>
#include <QBrush>
#include <QDebug>
#include <QGraphicsItem>
#include <QGraphicsLayoutItem>
#include <QGraphicsLinearLayout>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QPen>
class MyShape : public QGraphicsRectItem, public QGraphicsLayoutItem {
public:
MyShape(void) {
setPen(QPen(QBrush(Qt::black), 1));
setBrush(QBrush(Qt::green));
setRect(0, 0, 20, 20);
}
virtual QSizeF sizeHint(Qt::SizeHint which,
const QSizeF& constraint = QSizeF()) const {
Q_UNUSED(which);
Q_UNUSED(constraint);
return boundingRect().size();
}
virtual void setGeometry(const QRectF& rect) {
setPos(rect.topLeft());
}
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
QGraphicsScene scene;
MyShape* shape1 = new MyShape;
MyShape* shape2 = new MyShape;
MyShape* shape3 = new MyShape;
scene.addItem(shape1);
scene.addItem(shape2);
scene.addItem(shape3);
QGraphicsLinearLayout* layout = new QGraphicsLinearLayout;
layout->addItem(shape1);
layout->addItem(shape2);
layout->addItem(shape3);
QGraphicsWidget* container = new QGraphicsWidget;
container->setLayout(layout);
scene.addItem(container);
container->setPos(300, 300); // This doesn't appear to have any affect
// Item for indicating origin
QGraphicsRectItem* tmp = scene.addRect(0, 0, 2, 2, QPen(),
QBrush(Qt::green));
tmp->setPos(0, 0);
qDebug() << tmp->scenePos();
qDebug() << container->scenePos();
QGraphicsView view;
view.setScene(&scene);
view.centerOn(0, 0);
view.show();
return app.exec();
}
Then, I try to move the QGraphicsWidget within the scene by calling setPos(), but it doesn't appear to work (the QGraphicsItems remain in the same place). However, something appears to happen since the scrollbars change. It seems that the QGraphicsWidget moves, without taking the QGraphicsItems along with it.
Why?
EDIT:
By suggestion from DerManu, I changed the inheritance of MyShape to QGraphicsWidget, and with the following code, it works:
#include <QApplication>
#include <QBrush>
#include <QDebug>
#include <QGraphicsItem>
#include <QGraphicsLayoutItem>
#include <QGraphicsLinearLayout>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QPen>
class MyShape : public QGraphicsWidget {
public:
MyShape(void) {
setMinimumSize(20, 20);
setMaximumSize(20, 20);
setPreferredSize(20, 20);
}
QRectF boundingRect(void) const {
QRectF box(0, 0, 22, 22);
box.translate(box.center() * -1);
return box;
}
void paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget) {
Q_UNUSED(option);
Q_UNUSED(widget);
// Set box border appearance
painter->setPen(QPen(Qt::black, 1));
// Set box background appearance
painter->setBrush(QBrush(Qt::green));
QRectF box(0, 0, 20, 20);
box.translate(box.center() * -1);
painter->drawRect(box);
}
};
int main(int argc, char** argv) {
QApplication app(argc, argv);
QGraphicsScene scene;
MyShape* shape1 = new MyShape;
MyShape* shape2 = new MyShape;
MyShape* shape3 = new MyShape;
scene.addItem(shape1);
scene.addItem(shape2);
scene.addItem(shape3);
QGraphicsLinearLayout* layout = new QGraphicsLinearLayout(Qt::Vertical);
layout->addItem(shape1);
layout->addItem(shape2);
layout->addItem(shape3);
QGraphicsWidget* container = new QGraphicsWidget;
container->setLayout(layout);
scene.addItem(container);
container->setPos(200, 200); // This doesn't appear to have any affect
scene.setSceneRect(-300, -300, 600, 600);
// Item for indicating origin
QGraphicsRectItem* tmp = scene.addRect(0, 0, 2, 2, QPen(),
QBrush(Qt::green));
tmp->setPos(0, 0);
qDebug() << tmp->scenePos();
qDebug() << container->scenePos();
QGraphicsView view;
view.setScene(&scene);
view.centerOn(0, 0);
view.show();
return app.exec();
}
So what is it that QGraphicsWidget provides that I missed in the original code such that using setPos on the container item correctly moves the position of the MyShape items?

Resources