【问题标题】:QGraphicsView flickersQGraphicsView 闪烁
【发布时间】:2012-06-19 17:06:40
【问题描述】:

我想为我女朋友的学士论文写一个改变失明的程序。它显示 X 毫秒的图片,显示一个简短的“闪烁图像”(在本例中为灰色),然后显示与第一个图像略有不同的图像。然后又是一个闪烁的图像。

然后一切从头开始。它工作正常,只有图形伪影。我认为画布/ QGraphicsView 刷新它的速度不够快,因此它们在刷新期间是“线条”。

图像显示时间:70 ms,闪烁时间:30 ms。所以它的 100 毫秒 = 10 FPS/秒。我虽然不使用 gpu 也可以做到这一点。但看起来不是。

我可以使用双缓冲或其他方式来避免 GPU 问题吗?或者我需要使用 QGL 吗? 它大约 1 兆字节的图像。

我加载它们一次,我认为只是显示它们。也许我在场景中做错了事。

我会附上我的源代码,也许你有一些想法。

亲切的问候:)

#ifndef PICTURES_H
#define PICTURES_H

#include <QMainWindow>
#include <QImage>
#include <QPixmap>
#include <QGraphicsPixmapItem>
#include <iostream>
#include <QDir>
#include <QGraphicsScene>
#include <QDebug>
#include <QTimer>


namespace Ui {
class pictures;
}

class pictures : public QMainWindow
{
    Q_OBJECT

public:
    explicit pictures(QWidget *parent = 0);
    ~pictures();

    void loadPics();
    void showPics();

public slots:
    void stopClicked();
    void clearPictures();
    void timePassed();
    void changeImage();
    void changeImageGrey();

private:
    int counter;
    int image_counter;
    int stop_time;
    Ui::pictures *ui;
    QVector<int> times;
    QTimer* timer;
    QTimer* timerImageChange;
    QTimer* timerGrey;

    int imageChangeTime;
    int greyTime;

    QVector<QGraphicsPixmapItem*> images;
    QGraphicsScene* scene;
    QGraphicsScene* scene_grey;
    QGraphicsPixmapItem* item1;
};

#endif // PICTURES_H


#include "pictures.h"
#include "ui_pictures.h"

pictures::pictures(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::pictures), times()
{
    counter = 1;
    stop_time = 0;
    image_counter = 0;
    timer = new QTimer(this);
    timerGrey = new QTimer(this);
    timerImageChange = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timePassed()));
    connect(timerImageChange, SIGNAL(timeout()), this, SLOT(changeImageGrey()));
    connect(timerGrey, SIGNAL(timeout()), this, SLOT(changeImage()));

    greyTime = 200;
    imageChangeTime = 500;


    qDebug() << "Hello im here in pictures";

    ui->setupUi(this);
    this->loadPics();
    connect(ui->pushButtonStop, SIGNAL(clicked()), this, SLOT(stopClicked()));
    connect(ui->pushButtonNext, SIGNAL(clicked()), this, SLOT(clearPictures()));

    timer->start(10);
    timerImageChange->start(imageChangeTime);
}

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

void pictures::loadPics()
{
    qDebug() << QDir::toNativeSeparators((QDir::current().absolutePath() + QDir::separator () + "debug" + QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"1.jpg"));
    //QImage imageOne(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" + QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"1.jpg"));
    //QImage imageTwo(QString("./pics/")+counter+"/2.png");
    //QImage imageThree(QString("./pics/")+counter+"/3.jpg");
    //QImage imageFour(QString("./pics/")+counter+"/2.png");

    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"1.jpg")));
    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"2.jpg")));
    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"3.jpg")));
    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"4.jpg")));


    //QGraphicsPixmapItem* item1( QPixmap::fromImage(imageOne));
    item1 = images[image_counter];
    //QGraphicsPixmapItem item2( QPixmap::fromImage(imageTwo));
    //QGraphicsPixmapItem item3( QPixmap::fromImage(imageThree));
    //QGraphicsPixmapItem item4( QPixmap::fromImage(imageFour));
    scene = new QGraphicsScene;
    scene_grey = new QGraphicsScene;

    int maximum = item1->boundingRect().width() > item1->boundingRect().height() ? item1->boundingRect().width() : item1->boundingRect().height();
    int dimension_width  = ui->graphicsView->rect().width();
    int dimension_height = ui->graphicsView->rect().height();

    //int biggest_canvas_dimension = (((float)item1->boundingRect().width())/dimension_width) > (((float)item1->boundingRect().height())/dimension_height) ? dimension_width : dimension_height;
    int biggest_canvas_dimension = dimension_width > dimension_height ? dimension_width : dimension_height;

    if(maximum > ui->graphicsView->rect().width() || maximum > ui->graphicsView->rect().height())
    {
        dimension_width = (int) (item1->boundingRect().width() * ((float)(biggest_canvas_dimension )/maximum));
        dimension_height = (int) (item1->boundingRect().height() * ((float)(biggest_canvas_dimension)/maximum));
        item1->setPixmap(item1->pixmap().scaled(dimension_width,dimension_height));

        qDebug() << "Width: " << dimension_width << " Height " << dimension_height << " Pic High" << item1->boundingRect().height();
    }

    //item1->setPixmap(item1->pixmap().scaled(QSize(ui->graphicsView->rect().width(), ui->graphicsView->rect().height())));
    scene->setSceneRect(ui->graphicsView->rect());
    scene->addItem(item1);

    scene_grey->setSceneRect(ui->graphicsView->rect());
    scene_grey->addItem(images[1]);


    ui->graphicsView->setScene(scene);
    ui->graphicsView->adjustSize();

    //ui->graphicsView->show();


}

void pictures::timePassed()
{
    stop_time += 10;
}

void pictures::stopClicked()
{
    timerImageChange->stop();
    timerGrey->stop();
    times.append(stop_time);
    ui->pushButtonStop->setEnabled(false);
    ui->pushButtonNext->setEnabled(true);
    counter++;
    qDebug() << "Time: " << stop_time;

    stop_time = 0;
    timer->stop();
}

void pictures::clearPictures()
{
    scene->deleteLater();
    images.clear();
    loadPics();
    ui->pushButtonStop->setEnabled(true);
    ui->pushButtonNext->setEnabled(false);
    timer->start(10);
    timerImageChange->start(imageChangeTime);
}

void pictures::changeImageGrey()
{
    timerGrey->start(greyTime);
    timerImageChange->stop();
    image_counter = (image_counter+1)%4;

    //scene_grey->removeItem(scene_grey->items().at(0));
    //scene_grey->addItem(images[image_counter]);

    scene->removeItem(scene->items().at(0));
    scene->addItem(images[image_counter]);



    /*int maximum = item1->boundingRect().width() > item1->boundingRect().height() ? item1->boundingRect().width() : item1->boundingRect().height();
    int dimension_width  = ui->graphicsView->rect().width();
    int dimension_height = ui->graphicsView->rect().height();

    int biggest_canvas_dimension = dimension_width > dimension_height ? dimension_width : dimension_height;

    if(maximum > ui->graphicsView->rect().width() || maximum > ui->graphicsView->rect().height())
    {
        dimension_width = (int) (item1->boundingRect().width() * ((float)(biggest_canvas_dimension )/maximum));
        dimension_height = (int) (item1->boundingRect().height() * ((float)(biggest_canvas_dimension)/maximum));
        item1->setPixmap(item1->pixmap().scaled(dimension_width,dimension_height));
    }*/
    //scene->setSceneRect(ui->graphicsView->rect());

    //ui->graphicsView->setScene(scene_grey);

}

void pictures::changeImage()
{
    timerImageChange->start(imageChangeTime);
    timerGrey->stop();
    image_counter = (image_counter+1)%4;

    qDebug() << "    item1 = images[" + QString::number(image_counter) + "]";

    scene->removeItem(scene->items().at(0));

    item1 = images[image_counter];

    //qDebug() << QDir::toNativeSeparators((QDir::current().absolutePath() + QDir::separator () + "debug" + QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+ QString::number(image_counter+1) +".jpg"));


    int maximum = item1->boundingRect().width() > item1->boundingRect().height() ? item1->boundingRect().width() : item1->boundingRect().height();
    int dimension_width  = ui->graphicsView->rect().width();
    int dimension_height = ui->graphicsView->rect().height();

    int biggest_canvas_dimension = dimension_width > dimension_height ? dimension_width : dimension_height;

    if(maximum > ui->graphicsView->rect().width() || maximum > ui->graphicsView->rect().height())
    {
        dimension_width = (int) (item1->boundingRect().width() * ((float)(biggest_canvas_dimension )/maximum));
        dimension_height = (int) (item1->boundingRect().height() * ((float)(biggest_canvas_dimension)/maximum));
        item1->setPixmap(item1->pixmap().scaled(dimension_width,dimension_height));
    }

    //item1->setPixmap(item1->pixmap().scaled(QSize(ui->graphicsView->rect().width(), ui->graphicsView->rect().height())));
    //scene->setSceneRect(ui->graphicsView->rect());
    scene->addItem(item1);
    //ui->graphicsView->setScene(scene);

    //ui->graphicsView->setScene(scene);
    //ui->graphicsView->adjustSize();

    //ui->graphicsView->show();

}

【问题讨论】:

    标签: qt user-interface qgraphicsview double-buffering


    【解决方案1】:

    请记住,如果您的显示器刷新率为 60 Hz,则每张图像都会在 16 毫秒内重绘一次。您不能以 30 毫秒之类的精确时间进行绘制,只能以 16.666 毫秒的时间间隔进行计时。而且至少在 Windows 中,您无法轻易找出显示器中显示的图像何时会发生变化。如果您的代码显示图像,例如 10 毫秒,那么您要么看到图像,要么看不到。如果您将图像显示 25 毫秒,您将看到图像一次(16.666 毫秒)或两次(33.333 毫秒)。

    如果您真的想要精确的计时,我建议您使用 OpenGL,您可以使用显示器的垂直同步信息来计时。

    您在绘图过程中看到的线条可能是tearing。您也可以通过使用显示器的垂直同步信息来避免这种情况。

    您还使用 Qt 的计时器来计算 10 毫秒的间隔。那是行不通的。超时时间至少为 10 毫秒,但不能保证正好是 10 毫秒。实际上它更多,因此 100 次超时的总时间可能在 1100 毫秒左右。甚至更多,取决于您的操作系统。在 Windows 中,默认计时器分辨率为 16 毫秒。然后 100 次超时加起来约为 1700 毫秒。您可以使用timeBeginPeriod 更改计时器分辨率。

    要获得更准确的计时,请在您要等待的时间段内启动计时器。如果您想在 70 毫秒后执行某项操作,请将计时器间隔更改为 70 毫秒,而不是设置 7 次 10 毫秒超时。

    【讨论】:

    • 我支持 Roku 的见解。通常,您可能希望使用QElapsedTimer 来检查自某个引用以来实际经过了多少时间,并根据实时时间的流逝采取行动,而无需假设计时器事件何时触发。将计时器设置为在您希望时触发,但在 timerEvent 或您的插槽内,根据实时距离选择要显示的内容。
    • 我现在使用 16 秒间隔,因为它似乎更准确。现在很漂亮,但工作更少:P。我尝试将 QGLWidget 作为视口(将 opengl 添加到 pro 文件中)以避免撕裂,这似乎是问题所在。谢谢你的帮助:)
    猜你喜欢
    • 2011-05-09
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多