0

As the title says I am trying to have my QGraphicsView blinking 1 second in red, 1 second in green and 1 second in blue and after that the loop start over again. After doing a lot of research in the past couple of days I didn't have a lot of luck as the main problem is that I am not sure I need to subclass QGraphicsView to obtain the effect I am looking for. I came across some references that I inserted below saying that for this type of problems QPropertyAnimation seems to be the right direction. Although setting a QTimer could also be a choice.

Below the small verifiable example. I wrote minimal code:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QPropertyAnimation>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QGraphicsView *mView;
    QGraphicsScene *mScene;
    QPropertyAnimation *mAnimation;
};
#endif // MAINWINDOW_H

**mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTimer>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mView = new QGraphicsView();
    mScene = new QGraphicsScene();
    ui->graphicsView->setScene(mScene);
    // Starting with a gray background
    ui->graphicsView->setBackgroundBrush(QColor(Qt::gray));

    // Setting a timer that changes the color every second
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000);

}

MainWindow::~MainWindow()
{
    delete ui;
}

mygraphicsview.h

#ifndef MYGRAPHICSVIEW_H
#define MYGRAPHICSVIEW_H
#include <QGraphicsView>
class MyGraphicsView : public QGraphicsView
{
public:
    MyGraphicsView();
};

#endif // MYGRAPHICSVIEW_H

**mygraphicsview.cpp

#include "mygraphicsview.h"

MyGraphicsView::MyGraphicsView()
{}

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

In case you would like to see the .ui I am also sharing the file:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>277</width>
    <height>228</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <widget class="QGraphicsView" name="graphicsView"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>277</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

I have been researching the possibility to have a QGraphicsView blinking 1 second in red, 1 second in green and 1 second in blue and after that the loop start over again.

The only source I was able to find providing a complete example was in PyQt, for which I am not familiar with. The source is here and also this one.

The most important clue I got out of these examples is that, in particluar the last one, uses QState and QStateMachine. I am not familiar at all with these two features of Qt though and am struggling a little bit because of that.

Also I came across this partial example, and the good thing of this is that I learned how to set the QTimer useful for the 1s interval blinking.

Also because I am dealing with a QGraphicsView I have the feeling that void paintEvent(QPaintEvent *) override should be used.

Thank you very much for pointing in the right direction and solve this issue.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
Emanuele
  • 2,194
  • 6
  • 32
  • 71
  • `QPropertyAnimation` is not a bad solution but you can't use it in this case because there is no `property` that allow to directly change the background color, you can use QPalette but it doesn't work with `QPropertyAnimation`, a possible solution is indeed to reimplement `paintEvent()` but there is many solution... with `QGraphicsScene`, with the `QGraphicsView` etc.. – thibsc Apr 30 '20 at 22:37

1 Answers1

1

Use QPropertyAnimation is a problem here because the list of supported type is:

Int, UInt, Double, Float, QLine, QLineF, QPoint
QPointF, QSize, QSizeF, QRect, QRectF, QColor

And if you look the available properties of the QGraphicsView class hierarchy

QWidget properties
QFrame properties
QAbstractScrollArea properties
QGraphicsView properties

There is no interesting properties to pass to the QPropertyAnimation because QPalette and QString is not supported to play with setPalette() and styleSheet() and there is no variable to directly change the background color.


A solution is to subclass QGraphicsView:
graphicsview.h:

#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H

#include <QGraphicsView>
#include <QTimer>

class GraphicsView : public QGraphicsView
{
    Q_OBJECT
public:
    GraphicsView(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *evt) override;

private slots:
    void changeBackgroundColor();

private:
    int color_index;
    QTimer timer;
    const QColor colors[3] = { Qt::red, Qt::green, Qt::blue };

};

#endif // GRAPHICSVIEW_H

graphicsview.cpp:

#include "graphicsview.h"

GraphicsView::GraphicsView(QWidget *parent)
    : QGraphicsView(parent)
{
    color_index = -1;
    connect(&timer, SIGNAL(timeout()), this, SLOT(changeBackgroundColor()));
    timer.start(1000);
}

void GraphicsView::paintEvent(QPaintEvent *evt)
{
    QGraphicsView::paintEvent(evt);

    QPainter painter(viewport());
    painter.fillRect(viewport()->rect(), colors[color_index]);
}

void GraphicsView::changeBackgroundColor()
{
    if (color_index == 2){
        color_index = 0;
    } else {
        color_index++;
    }
    viewport()->update(rect());
}
thibsc
  • 3,747
  • 2
  • 18
  • 38
  • Thank you very much for the very detailed explanation. I applied your suggestion at it works exactly as I wanted. I see also why you mentioned the `QPropertyAnmation` limitations. Thanks for your time! Very much appreciated!! :) – Emanuele May 02 '20 at 20:46