Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: borkk от Апрель 19, 2013, 11:38



Название: [РЕШЕНО] Мерцание при анимации
Отправлено: borkk от Апрель 19, 2013, 11:38
Добрый день!
Разработал свой класс ArrowWidget (на основе QWidget), состоящий из нескольких стрелок (направленных вверх или вниз). При нажатии на кнопку стрелки должны либо начать анимацию, либо закончить (в зависимости от нажатой кнопки), рисую при помощи QPainter-а, массивом полигонов (QPolygon), анимация реализована при помощи QPropertyAnimation. Обнаружил проблему, если эти стрелочки отрисовывать в виджете QWidget или просто в окне MainWindow, то при анимации мерцает нижняя стрелка, причем мерцание начинается только после повторного нажатия на клавишу анимации. Видео с примером по ссылке http://youtu.be/3gHhM-3yAeA (http://youtu.be/3gHhM-3yAeA)
Решил проблему при помощи Graphics View Framework, создал сцену (QGraphicsScene), вид (QGraphicsView), вид сделал родительским для экземпляра ArrowWidget (экземпляр называется myWidget) и добавил этот экземпляр на сцену. Теперь при нажатии клавиш анимации мерцания не возникает.
Соответственно вопрос, корректно ли решение? Есть ли другие варианты? А то мне кажется, что это как из пушки по воробьям...

ArrowWidget описание класса
Код:
class ArrowWidget : public QWidget
{
    Q_OBJECT
public:
    ArrowWidget(QWidget *parent = 0);
    virtual ~ArrowWidget() {}
    void paintEvent(QPaintEvent *pe);
    bool isDown();
    bool isUp();
    void setDown();
    void setUp();
    void setGoingUp(bool b);
    bool isGoingUp();
    void setGoingDown(bool b);
    bool isGoingDown();

private:
    bool posArrows; // 0 - down; 1 - up
    bool goingUp;
    bool goingDown;
    QPropertyAnimation *animation;
};

ArrowWidget конструктор и методы
Код:
ArrowWidget::ArrowWidget(QWidget *parent) : QWidget(parent)
{
    resize(parent->size());
    posArrows = false;
    animation = new QPropertyAnimation(this, "geometry");
    animation->setDuration(1000);
    animation->setLoopCount(-1);
    animation->setStartValue(QRect(0, 0, this->width(), this->height()));
//    setAutoFillBackground(true);
//    setAttribute(Qt::WA_OpaquePaintEvent,true);
}

void ArrowWidget::paintEvent(QPaintEvent *pe)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setBrush(QBrush(Qt::black));
    painter.setPen(QPen(Qt::black));

    const int arrowsNum = (height()/13);
    QPolygon arrows[arrowsNum];
    if(!posArrows) {
        for(int i = 0; i < arrowsNum; i++) {
            arrows[i] << QPoint(1,(11*i)+2+(i*2)) << QPoint(19,(11*i)+2+(i*2)) << QPoint(10,(11*(i+1))+2+i*2);
            painter.drawPolygon(arrows[i]);
        }
    } else {
        for(int i = 0; i < arrowsNum; i++) {
            arrows[i] << QPoint(1,(11*(i+1))+2+(i*2)) << QPoint(19,(11*(i+1))+2+(i*2)) << QPoint(10,(11*i)+2+i*2);
            painter.drawPolygon(arrows[i]);
        }
    }
}

bool ArrowWidget::isUp()
{
    if(posArrows == true)
        return true;
    else
        return false;
}

void ArrowWidget::setUp()
{
    posArrows = true;
    update();
}

void ArrowWidget::setGoingUp(bool b)
{
    setUp();
    animation->setEndValue(QRect(0, -13, this->width(), this->height()));
    if(b) {
        animation->stop();
        animation->start();
    } else {
        animation->stop();
        update();
    }
}

bool ArrowWidget::isGoingUp()
{
    return goingUp;
}

MainWindow.h
Код:
class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
private slots:
    void on_pushButton_clicked();
    void on_pushButton_3_clicked();
    void on_pushButton_2_clicked();
    void on_pushButton_4_clicked();

private:
    Ui::MainWindow *ui;
    ArrowWidget *myWidget;
};

MainWindow.cpp
Код:
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //Если сделать родителем ui->widget, и закомментировать строчки ниже, стрелочки будут мерцать
    myWidget = new ArrowWidget(ui->graphicsView);

    QGraphicsScene *scene = new QGraphicsScene;
    ui->graphicsView->setScene(scene);
    ui->graphicsView->setBackgroundBrush(QColor(240,240,240));

    scene->addWidget(myWidget);

}

архив с проектом во вложении


Название: Re: Мерцание при анимации
Отправлено: Bepec от Апрель 19, 2013, 12:03
Такое чуйство, что у вас идёт двойная перерисовка или двойной вызов анимации. В результате чего оно и дёргается.

Код не смотрел, нет времени :)


Название: Re: Мерцание при анимации
Отправлено: borkk от Апрель 19, 2013, 12:09
при нажатии на клавишу вызывается метод
Код:
animation->stop();
затем
Код:
animation->start();
. Насчет двойной перерисовки не могу знать, где посмотреть? Как будет время, гляньте код, может подскажете чего.


Название: Re: Мерцание при анимации
Отправлено: Bepec от Апрель 19, 2013, 12:15
Возможно в выходные посмотрю. А мб кто нибудь решит раньше.

НЕНАВИЖУ, НЕНАВИЖУ компиляторы, не поддерживающие стандарт :D Массив динамической длины... Это ж ппц.


Название: Re: Мерцание при анимации
Отправлено: Bepec от Апрель 22, 2013, 13:58
Никаких артефактов наподобие тех, что в вашем видео не обнаружил. спокойно всё ковыляет.


Название: Re: Мерцание при анимации
Отправлено: borkk от Апрель 23, 2013, 13:09
Ага, как только убрал массив динамической длины стало нормально отображаться)
Вот так вот временное становится постоянным и мешает разработке. Спасибо!


Название: Re: Мерцание при анимации
Отправлено: Bepec от Апрель 23, 2013, 13:24
Вы ещё подумайте, если это у вас используется вне сцены, мб стоит просто отрисовывать и не загромождать свои программы ещё и сценами?

PS на каждый элемент по сцене - это ж ппц будет.


Название: Re: Мерцание при анимации
Отправлено: borkk от Апрель 23, 2013, 13:38
Нет, у меня мерцало при анимации без сцены, когда я отрисовывал массив, именно поэтому добавил сцену (см. первый пост, написал, что победил проблему, но кажется, что это как из пушки по воробьям). Сейчас убрал сцены и вид и просто создаю QPolygon и рисую им в цикле
Код:
QPolygon arrows;
   for(int i = 0; i < arrowsNum; i++) {
       arrows.clear();
       arrows << QPoint(1,(11*i)+2+(i*2)) << QPoint(19,(11*i)+2+(i*2)) << QPoint(10,(11*(i+1))+2+i*2);
       painter.drawPolygon(arrows);
   }
Никаких мерцаний при анимации не наблюдаю.


Название: Re: [РЕШЕНО] Мерцание при анимации
Отправлено: Bepec от Апрель 23, 2013, 13:54
Слава богу. :)