PDA

View Full Version : How to update a graphics item immediately??



Rabbitl96l
2nd April 2015, 17:45
I am making a list of blue rectangles and then try to change color of them one by one to the end of the list. Here is my source code:

traverse() in dialog.cpp

void Dialog::traverse()
{
Node *cur = head;
while (cur)
{
colorAnimation = new QPropertyAnimation(cur->square, "color");
colorAnimation->setDuration(4000);
colorAnimation->setKeyValueAt(0.0, RED);
colorAnimation->setKeyValueAt(0.9, RED);
colorAnimation->setKeyValueAt(1.0, CYAN);
colorAnimation->start();

clock_t waiter = clock() + 4 * CLOCKS_PER_SEC;
while (clock() < waiter);
cur = cur->next;
}
}

square.h

const int CYAN = 0;
const int RED = 1;
class Square : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_PROPERTY(int color MEMBER color WRITE setColor)
public:
Square();
Square(int n);
~Square();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void setColor(int newColor);
private:
int color;
int order;
};

square.cpp

#include "square.h"

Square::Square()
{
color = CYAN;
order = 0;
}

Square::Square(int n)
{
color = CYAN;
order = n;
}

Square::~Square()
{
}

QRectF Square::boundingRect() const
{
return QRectF(X_START + order*HDISTANCE, Y_START, B_WIDTH, HEIGHT);
}

void Square::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rect = QRectF(X_START + order*HDISTANCE + LINE, Y_START, WIDTH, HEIGHT);
QPen pen(Qt::blue);
pen.setCapStyle(Qt::RoundCap);
QBrush brush(Qt::cyan);

if (color == RED)
{
brush.setColor(Qt::red);
}
else if (color == CYAN)
{
brush.setColor(Qt::cyan);
}

painter->fillRect(rect, brush);
painter->drawRect(rect);
}

void Square::setColor(int newColor)
{
color = newColor;
update();
}

It happens to be a group of rectangles changing to red at the same time. I think it is because the update() function doesn't repaint the item immediately, but I can not use the repaint() function to modify a graphics item. Can anyone suggest a way to repaint the item immediately? Thanks you very much.

stampede
2nd April 2015, 20:36
colorAnimation->setDuration(4000);
colorAnimation->setKeyValueAt(0.0, RED);
colorAnimation->setKeyValueAt(0.9, RED);
colorAnimation->setKeyValueAt(1.0, CYAN);
I'm wondering what are you trying to visualize, as your "animation" is a just a single color 99% of the time.
What's wrong with simple "setColor" call instead of creating a (probably leaking) animation object each time ?
Btw. don't use busy waiting (the "while" hack) as it is almost never needed in Qt applications.

If I understand your problem correctly, you are trying to change the color of each item one by one with some kind of delay between each change. If this is correct, then maybe try to use a QTimer with a proper interval and simply call "setColor" on the rectangles one after another.

Rabbitl96l
3rd April 2015, 12:34
I have tried to use QTimer, but the rectangles still change color at the same time because of the update( ) function.


void Dialog::traverse()
{
Node *cur = list.getHead();
timer = new QTimer(this);
while (cur)
{
connect(timer, SIGNAL(timeout()), cur->square, SLOT(changeColor()));
timer->start(3000);
cur = cur->next;
}
}

wysota
3rd April 2015, 13:01
Lose the while loop. Start the timer and in the timeout slot modify one item. Next time timeout is invoked modify the next item and so on.

d_stranz
3rd April 2015, 18:54
Lose the while loop

I think the OP's idea is to change the colors of all of the squares "simultaneously" (as best as that can be accomplished). That's why the multiple timers / animations and the while loop.

From my understanding of QPropertyAnimation, the external QTimer is completely unnecessary - the animation does its own internal timing. It is most likely this code:


clock_t waiter = clock() + 4 * CLOCKS_PER_SEC;
while (clock() < waiter);

and the fact that the event look is never executed during that time which results in the failure to update the colors as planned. But there isn't enough context in the source code that is shown to figure out what the real problem is.

wysota
3rd April 2015, 21:13
I think the OP's idea is to change the colors of all of the squares "simultaneously" (as best as that can be accomplished).
I don't know. He said it was incorrect behavior that they did change all at once:


the rectangles still change color at the same time


That's why the multiple timers / animations and the while loop.
I think he thought starting a timer would synchronously delay execution.


But there isn't enough context in the source code that is shown to figure out what the real problem is.

I agree :)

d_stranz
4th April 2015, 04:08
but the rectangles still change color at the same time

If I read between the lines, I think he means that the animation isn't occurring - the color just goes from blue to red without the fade in. At least that is my interpretation, and the code he did post would result in that behavior, I think.

Am I correct in assuming that time 0 is established when the animation's start() slot is called, and that if his code doesn't return to the event loop before the duration time has elapsed, then the animation will immediately go to the end state?

Rabbitl96l
4th April 2015, 04:40
Ok, I have solved it. Thank you guys very much for help.

wysota
4th April 2015, 12:22
...and we won't ever know what the problem was :)