Qt中的实时像素绘图

时间:2014-02-02 21:46:50

标签: c++ qt

我的应用程序显示一个长的科学垂直滚动图片(1024 x 99999999 ... px)作为QPixmap 1024x128块的序列。这允许我通过从表中选择所需的块来以最小的CPU成本滚动图片:block_id = y_coord/128。此外,QPixmap是用于快速屏幕输出的首选“像素容器”。

但是现在我有一个新数据流进入应用程序,需要添加新数据并显示在长图的底部。最小部分:1024x1(一行)。此外,我想尽快显示每一个新行(接近实时)。 128行的每个新部分将被“打包”到QPixmap,但在我收到足够数据之前,我无法构建整个块。

我应该考虑采用什么方法来显示新数据?

此视频提供了“添加新数据行”的概念,但在我的情况下,流量会上升:http://www.youtube.com/watch?v=Dy3zyQNK7jM

3 个答案:

答案 0 :(得分:1)

您可以直接修改QPixmaps的底行和update()窗口(如果底行在范围内)。

您可能会发现使用QImage对于半成品行更有效,具体取决于您更新/重绘的速度。

答案 1 :(得分:0)

这是我放在一起的一个简单例子。我不知道它是否是最有效的,但它展示了你正在看的基本想法:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QVector>
#include <QGraphicsScene>
#include <QTimerEvent>

#define TILE_HEIGHT 128
#define TILE_WIDTH 1024

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    QPixmap generateLine();
public slots:
    void timerEvent(QTimerEvent *);
private:
    QGraphicsView * m_view;
    QGraphicsScene * m_scene;
    QVector <QGraphicsPixmapItem *> m_tiles;
    QVector <QGraphicsPixmapItem *> m_lineBuffer;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

#include <QPixmap>
#include <QtGlobal>
#include <QDateTime>
#include <QTimer>
#include <QPaintEngine>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setFixedWidth(TILE_WIDTH);
    this->setCentralWidget(m_view = new QGraphicsView());
    m_scene = new QGraphicsScene;
    m_view->setScene(m_scene);

    QPixmap p(TILE_WIDTH, TILE_HEIGHT);
    p.fill(Qt::black);
    m_tiles.append(new QGraphicsPixmapItem(p));
    m_tiles.last()->setPos(0,0);
    m_scene->addItem(m_tiles.last());

    qsrand(QDateTime::currentMSecsSinceEpoch());

    this->startTimer(0);
}

MainWindow::~MainWindow()
{

}

void MainWindow::timerEvent(QTimerEvent *)
{
    // if your generated data is on another thread, you may want to do some thread
    // synchronization with a Mutex and a Mutex Locker so you don't stomp on your
    // buffers

    // static bool busy = false;
    // static int skipCount = 0;
    // if(busy)
    // { 
    //    skipCount++;
    //     qDebug() << "Skipped Line count =" << skipCount;
    //     return;
    // }
    // busy = true;

    // grab a new line
    QPixmap linePix = generateLine();
    int y = m_tiles.size()*TILE_HEIGHT + m_lineBuffer.size()*1;

    // append it to the line buffer
    m_lineBuffer.append(new QGraphicsPixmapItem(linePix));

    // add it to the scene
    m_scene->addItem(m_lineBuffer.last());
    m_lineBuffer.last()->setPos(0, y);

    // scroll it into view
    m_view->ensureVisible(m_lineBuffer.last());

    if(m_lineBuffer.size() >= TILE_HEIGHT)
    {
        // when the line buffer is "full"
        // or ready to be made into a tile

        // compile all the qpixmaps into a single "tile"
        static QRectF source(0,0, TILE_WIDTH, 1);
        QPixmap tile(TILE_WIDTH, TILE_HEIGHT);
        QPainter painter;
        painter.begin(&tile);
        for(int i = 0; i < m_lineBuffer.size(); i++)
        {
            painter.drawPixmap(QRectF(0, i, TILE_WIDTH, 1),
                               m_lineBuffer.at(i)->pixmap(),
                                       source);
        }
        painter.end();

        // add it into the tiles list
        m_tiles.append(new QGraphicsPixmapItem(tile));

        // add it to the scene
        m_tiles.last()->setPos(0, (m_tiles.size() - 1)*TILE_HEIGHT);
        m_scene->addItem(m_tiles.last());

        // scroll it into view
        m_view->ensureVisible(m_tiles.last());

        // Clean up the line buffer
        foreach(QGraphicsPixmapItem * pi, m_lineBuffer)
        {
            m_scene->removeItem(pi);
            delete pi;
        }
        m_lineBuffer.clear();
    }
    // busy = false;
}

QPixmap MainWindow::generateLine()
{
    // create a random pixmap of TILE_WIDTH x 1
    static int img_width = TILE_WIDTH;
    QImage img(img_width,1, QImage::Format_RGB16);
    for(int i = 0; i< img_width; i++)
    {
        img.setPixel(i, 0, qrand()%65536);
    }
    return QPixmap::fromImage(img);
}

的main.cpp

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.showMaximized();

    return a.exec();
}

答案 2 :(得分:0)

在当代Qt上,当使用光栅后端时,QPixmapQImage相比没有任何好处。所有内容都呈现给一个大的QImage后备缓冲区,然后缓冲到屏幕上。所以只需使用QImage

您可以拥有128像素高的QImage,但您只绘制已填充数据的部分。没有数据的部分要么没有绘制,要么悬挂在窗口的可见区域下面,因此实际上是不可见的。