Сон внутри цикла, использующего paintevent в qt С++

В основном то, что я хочу сделать, это нарисовать прямоугольники для каждого числа в моем списке. Чем больше число, тем больше прямоугольник. Моя проблема в том, что я действительно хочу сделать это шаг за шагом и ждать несколько секунд между каждым рисунком. Я искал несколько решений, но не могу заставить их работать в этом конкретном случае. Я видел, что могу использовать fflush для освобождения всего, что находится в буфере, но я не знаю, как я могу использовать его для этого.

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
int weight=300/lista.size;
int posx=weight;
for (int i=1; i<=lista.size; i++){
        List_node * node = list.get_element_at(i);
            int num=node->getValue(); //this returns the value of the node
        if (i==3){
                painter.setBrush(QBrush(Qt::red, Qt::SolidPattern)); // this line is to draw a rectangle with a different color. Testing purposes.
         }
        painter.drawRect(posx,400-(num*10),weight,num*10);
        sleep(1); //this sleep isn't working correctly.
        painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
        posx+=weight;
 }

Любая помощь могла бы быть полезна.


person Alejandro Gonzalez    schedule 21.09.2012    source источник


Ответы (1)


sleep() для этого не подойдет — он блокирует цикл событий Qt и не дает Qt выполнять свою работу, пока он находится в спящем режиме.

Что вам нужно сделать, так это сохранить одну или несколько переменных-членов, чтобы запомнить текущее состояние изображения, которое вы хотите нарисовать, и реализовать paintEvent() для рисования только этого текущего одиночного изображения. paintEvent() (как и любая функция, работающая в потоке GUI Qt) всегда должна возвращаться немедленно, а не засыпать или блокироваться.

Затем, чтобы реализовать часть анимации, настройте объект QTimer для вызова слота через регулярные промежутки времени (например, раз в 1000 мс или так часто, как вам нравится). Реализуйте этот слот, чтобы настроить ваши переменные-члены на их следующее состояние в последовательности анимации (например, прямоугольник_размер++ или что-то еще), а затем вызовите update() в вашем виджете. update() сообщит Qt как можно скорее снова вызвать paintEvent() для вашего виджета, поэтому ваш дисплей будет обновлен до следующего кадра вскоре после возврата вашего метода слота.

Ниже приведен тривиальный пример техники; при запуске он показывает, что красный прямоугольник становится все больше и меньше:

// begin demo.h
#include <QWidget>
#include <QTimer>

class DemoObj : public QWidget
{
Q_OBJECT

public:
   DemoObj();

   virtual void paintEvent(QPaintEvent * e);

public slots:
   void AdvanceState();

private:
   QTimer _timer;
   int _rectSize;
   int _growthDirection;
};

// begin demo.cpp
#include <QApplication>
#include <QPainter>
#include "demo.h"

DemoObj :: DemoObj() : _rectSize(10), _growthDirection(1)
{
   connect(&_timer, SIGNAL(timeout()), this, SLOT(AdvanceState()));
   _timer.start(100);   // 100 milliseconds delay per frame.  You might want to put 2000 here instead
}

void DemoObj :: paintEvent(QPaintEvent * e)
{
   QPainter p(this);
   p.fillRect(rect(), Qt::white);
   QRect r((width()/2)-_rectSize, (height()/2)-_rectSize, (_rectSize*2), (_rectSize*2));
   p.fillRect(r, Qt::red);
}

void DemoObj :: AdvanceState()
{
   _rectSize += _growthDirection;
   if (_rectSize > 50) _growthDirection = -1;
   if (_rectSize < 10) _growthDirection = 1;
   update();
}

int main(int argc, char ** argv)
{
   QApplication app(argc, argv);

   DemoObj obj;
   obj.resize(150, 150);
   obj.show();
   return app.exec();
}
person Jeremy Friesner    schedule 21.09.2012