Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QMovie, QLabel - don't play gif



  • Hi,
    I would like to do something like:
    In mainWindow I create label with gif movie and start play that movie. Next there are some QProcess ( cmd commands ). When commands will finished I would like to stop movie. So I wrote something like:

    QMovie movie(R"(pathToGif)");
            QLabel *labelGif = new QLabel(this);
            labelGif->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
            labelGif->setMovie(&movie);
            labelGif->show();
            labelGif->move(anotherPoint);
            movie.start();
                    
            proc = new QProcess;
            
            if(!function1())
            {
                varBool = false;
            }
    
            if(varBool)
            {
                QMessageBox *box = new QMessageBox;
                box->setIcon(QMessageBox::Information);
                box->setWindowTitle("title");
                box->setText("message");
    
                box->addButton("textBut1", QMessageBox::AcceptRole);
                box->addButton("textBu2", QMessageBox::RejectRole);
    
                if(!box->exec())
                {
                    proc->start(R"(anotherCMDCommand)");
                }
                delete box;
            }
    
            movie.stop();
            labelGif->hide();
            labelGif->setParent(nullptr);
            delete labelGif;
            labelGif = nullptr;
    

    In function1 there are some CMD commands.

    When I execute this code ( and varBool == false (so I don't create QMessageBox)) I don't see any label with gif.
    When I execute this code ( and varBool == true (so I create QMessageBox)) I see a label with gif, but movie is freeze. When I click ok or cancel in messageBox label is hide and delete ( I see only that freeze ).

    EDIT:
    Var proc ( QProcess ) always have proc->waitForFinished() and I know that all CMD commands are good and can be finished.


  • Moderators

    @qwe3 of course, you're blocking the event loop with your wait for finished call. It waits and does not update the ui.

    Please use the asynchronous api of QProcess



  • @J-Hilk But before I start some CMD command I have in code "label->show()", so why I can't see any label?

    I can't use something like "detached". How can I do what I want and don't use proc->startDetached()?


  • Moderators

    @qwe3 said in QMovie, QLabel - don't play gif:

    "label->show()", so why I can't see any label?

    simply, the effect of show (and hide btw) is only visible when the event loop is running, if you block it, the show/repainting will only happen once the event loop is running again

    I can't use something like "detached". How can I do what I want and don't use proc->startDetached()?

    I don't know why you can't but, ok.
    Move the QProcess part into it's own class (QOBJECT NOT QWidget based), and than use QThread to run an instance of your new class and use signals to inform your main thread/ui to update/start&stop the movie



  • @J-Hilk So do you think about something like:

    MyClass: public QThread
    {
    public:
    void run();
    }
    
    void run()
    {
    emit startMovie();
    cmdCommands();
    emit endMovie();
    }
    /////////////////////////////////
    in mainWindow constructor:
    {
    MyClass *myClass = new MyClass;
    connect(myClass, SIGNAL(startMovie()), this, SLOT(startMovieSlot()));
    connect(myClass, SIGNAL(endMovie()), this, SLOT(endMovieSlot()));
    myClass->run();
    }
    
    and in endMovieSlot I delete myClass and QLabel?
    

  • Moderators

    @qwe3 I went out of my way to describe the other Worker approach, not subclass QThread one, but in essence, yes



  • @J-Hilk I write code exactly which I write in my last message on this forum. My code execute cmd commands and emit signal start and stop, but I still don't see any movie.


  • Moderators

    @qwe3 startMovieSlot and endMovieSlot can you show the content of those ?



  • @J-Hilk

    void MainWindow::startMovieSlot()
    {
        labelGif->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
        labelGif->setMovie(movie);
        labelGif->show();
        labelGif->move(AnotherPoint);
        movie->start();
    }
    
    void MainWindow::endMovieSlot()
    {
        show(); // In mainWindow constructor I hide() mainWindow
        movie->stop();
        labelGif->hide();
        labelGif->setParent(nullptr);
        delete labelGif;
        delete myClass;
        myClass= nullptr;
        labelGif = nullptr;
    }
    

    I don't have any point on this forum ,so I have to wait 10 minutes beetwen two messages.


  • Moderators

    @qwe3

    is labelGif parentless or is mainWindow the parent ?
    If it's the parent, than hiding the parent will hide the label and possibly mess things up

    did you give it a defined size? Manually created QLabels do not have a default size and labels of size 0 are not shown as well

    I don't have any point on this forum ,so I have to wait 10 minutes beetwen two messages.

    in gave you an upvote, that should help



  • @J-Hilk
    Thank you for upvote :)

    QLabel has parent - mainWindow.

    When I execute label->setMovie(), label get size equally to gif size.

    EDIT

    I delete parent from QLabel and delete show() and hide() functions on class mainWindow. This is my constructor of mainWindow:

            movie = new QMovie(R"(pathToGif)");
            labelGif = new QLabel();
            myClass= new myClass;
            connect(myClass, SIGNAL(startMovie()), this, SLOT(startMovieSlot()));
            connect(myClass, SIGNAL(endMovie()), this, SLOT(endMovieSlot()));
            myClass->run();
    

    EDIT 2
    I still don't see movie


  • Moderators

    @qwe3 said in QMovie, QLabel - don't play gif:

    When I execute label->setMovie(), label get size equally to gif size.

    actually, it does not, I just made a small test and I had to manually resize the QLabel

    so, this example works perfectly fine for me:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QMovie>
    #include <QLabel>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr, const QString &str = QString("Hello World"));
        ~MainWindow();
    
    public slots:
        void startMovieSlot();
        void endMovieSlot();
    
    
    public slots:
    
    
    private:
        Ui::MainWindow *ui;
        QMovie *m = nullptr;
        QLabel *l = nullptr;
    
    };
    
    #endif // MAINWINDOW_H
    
    
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QTimer>
    
    MainWindow::MainWindow(QWidget *parent, const QString &str) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
    
        QTimer *stopAfter2Sec(new QTimer(this));
        connect(stopAfter2Sec, &QTimer::timeout, this, &MainWindow::endMovieSlot);
        stopAfter2Sec->setSingleShot(true);
        stopAfter2Sec->start(2000);
    
        QMetaObject::invokeMethod(this, &MainWindow::startMovieSlot, Qt::QueuedConnection);
        startMovieSlot();
    }
    
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::startMovieSlot()
    {
        if(!l){
            l = new QLabel(this);
            l->resize(240,152);
        }
        if(!m){
            m = new QMovie(":/Nyan-Cat.gif");
        }
        hide();
        l->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
        l->setMovie(m);
        l->show();
        m->start();
    }
    
    void MainWindow::endMovieSlot()
    {
        show();
        l->hide();
        m->stop();
    }
    


  • @J-Hilk Thank you, but I can't use this code because I don't know the time which CMD commands need, so I can't use QTimer(2000).

    I try change my code using your code, but still don't see a QLabel ( for example I resize QLabel ).


  • Moderators

    @qwe3 said in QMovie, QLabel - don't play gif:

    Thank you, but I can't use this code because I don't know the time which CMD commands need, so I can't use QTimer(2000).

    I don't have access to your code, so I created a Signal (via the timer) to trigger the end slot, to check if it works or not, in you case, that signal should be endMovie ()

    I try change my code using your code, but still don't see a QLabel ( for example I resize QLabel )

    let's back down than, do not apply a movie, simply set a text, see if that shows,
    Add qDebug statements to see if your slots are called

    show the label from the get go, see if anything is there



  • @J-Hilk
    My whole code:

    #include "mainwindow.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "QMessageBox"
    #include <QDebug>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
             ui->setupUi(this);
    
            QMessageBox::information(nullptr, "title", "message");
    
            myClass= new ClassXyz;
            connect(myClass, SIGNAL(startMovie()), this, SLOT(startMovieSlot()));
            connect(myClass, SIGNAL(endMovie()), this, SLOT(endMovieSlot()));
            myClass->run();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::startMovieSlot()
    {
        movie = new QMovie(R"(pathToGif)");
        labelGif = new QLabel(this);
        labelGif->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
        labelGif->setMovie(movie);
        labelGif->show();
        labelGif->move(500,500);
        movie->start();
    }
    
    void MainWindow::endMovieSlot()
    {
        show();
        movie->stop();
        labelGif->hide();
        labelGif->setParent(nullptr);
        delete labelGif;
        delete myClass;
        myClass = nullptr;
        labelGif = nullptr;
    }
    
    
    #include "classxyz.h"
    
    ClassXyz::ClassXyz()
    {
    
    }
    
    void ClassXyz::run()
    {
        startMovie();
    for(int i=0;i<1000;i++)
    {
            proc->start(R"(netsh show)"); // this is only equivalent for my commands
            proc->waitForFinished();
    }
        endMovie();
    }
    
    
    #ifndef CLASSXYZ_H
    #define CLASSXYZ_H
    #include <QThread>
    #include <QProcess>
    
    class ClassXyz: public QThread
    {
        Q_OBJECT
    public:
        ClassXyz();
        void run() override;
    private:
        QProcess *proc;
    
    signals:
        void endMovie();
        void startMovie();
    };
    
    #endif // CLASSXYZ_H
    
    
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "QProcess"
    #include <QMovie>
    #include <QLabel>
    
    #include "classxyz.h"
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    public slots:
        void startMovieSlot();
        void endMovieSlot();
    private:
        Ui::MainWindow *ui;
        QMovie *movie;
        QLabel *labelGif;
        ClassXyz*myClass;
    };
    #endif // MAINWINDOW_H
    
    

Log in to reply