qt - 在 Qt 中使用像素图或位图快速绘图

标签 qt plot bitmap repaint pixmap

我需要 Qt 中的快速绘图小部件,但我不想使用任何准备好的东西。 我有一些 float 数据,例如 QVector< float >数据,我需要在小部件上绘制它。但我不想使用 paintEventQPainter直接在上面。是否有机会将此数据转换为位图(像素图?)并直接加载它以显示在小部件上?如何从 float 创建位图?

最佳答案

如果绘画是开销大的,你可以把它移到另一个线程,这样它就不会锁定你的应用程序的事件循环,并且在完成时更新结果。

既然你想要任意绘图,那么“将数据转换为位图”确实没有神奇的方法,你必须使用 QPainter 来绘制你的东西。

这是一个如何使用异步绘图仪对象的简单示例:

class Plotter : public QObject {
    Q_OBJECT
public:
    Plotter(QSize size, QRectF range, QVector<double> data)
        : _size(size), _range(range), _data(data) { }

signals:
    void done(QImage);
    void cleanup();

public slots:
    void plot() {
        QElapsedTimer t;
        t.start();
        QImage img(_size, QImage::Format_ARGB32_Premultiplied);
        img.fill(Qt::white);
        QPainter p(&img);
        QPen pen(Qt::darkBlue);
        pen.setWidth(1);
        p.setPen(pen);
        for (int i = 0; i < _data.size(); i += 2) {
            p.drawPoint(map(_data[i], _data[i + 1]));
        }
        qDebug() << "plotted in" << t.elapsed() << "msec";
        emit done(img);
        emit cleanup();
    }

private:
    inline QPointF map(double x, double y) {
        return QPointF(_size.width() * (x / (_range.width() - _range.x())),
                       _size.height() * (y / (_range.height() - _range.y())));
    }

    QSize _size;
    QRectF _range;
    QVector<double> _data;
};

绘图仪是用它的大小、范围和数据参数创建的,我使用 QRectF 作为范围,基本上使用 x/width 和 y/height 作为水平和垂直范围。绘图仪是一个非常简单的实现,为了示例,它使用 map() 方法将数据点“规范化”到以线性方式绘制到的图像区域。我还添加了一个计时器来查看绘制所有点需要多长时间。

这是用于创建绘图、填充数据并显示结果的示例小部件:

class Widget : public QWidget {
    Q_OBJECT
public:
    Widget(QWidget * parent = 0) : QWidget(parent) {
        // prepping data
        QVector<double> data;
        data.reserve(200000);
        for (int i = 0; i < 200000; ++i) data.append((double)qrand() / RAND_MAX);

        // create plotter and thread
        Plotter * p = new Plotter(size(), QRectF(0, 0, 1, 1), data);
        QThread * thread = new QThread;
        p->moveToThread(thread);

        // do connections
        connect(thread, SIGNAL(started()), p, SLOT(plot()));
        connect(p, SIGNAL(done(QImage)), this, SLOT(updatePlot(QImage)));
        connect(p, SIGNAL(cleanup()), thread, SLOT(quit()));
        connect(thread, SIGNAL(finished()), p, SLOT(deleteLater()));
        connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

        thread->start();
    }

protected:
    void paintEvent(QPaintEvent *) {
        QPainter p(this);
        p.drawImage(QPoint(0, 0), plot);
    }

public slots:
    void updatePlot(QImage p) {
        plot = p;
        repaint();
    }

private:
    QImage plot;
};

在我的示例中,我使用 0-1 范围内的 200 000 个值填充数据。然后使用小部件的大小创建绘图仪,X 和 Y 的范围为 0-1,创建线程并将绘图仪移动到它,进行必要的连接并启动线程。启动后,线程将调用 plot() 插槽,它将绘图结果发送到小部件的 updatePlot() 插槽。当发送结果时,绘图仪将退出线程事件循环,这将删除绘图仪对象和线程,这样它们就不会泄漏。

至于这有多快,我的 i7 桌面在 8 毫秒内绘制了 200,000 个点,所以它无论如何都不慢。

关于qt - 在 Qt 中使用像素图或位图快速绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27190411/

相关文章:

python - PyQt 中的复杂模型项

html - PlotlyJS.jl "savehtml"未定义

删除 r 中绘图区域周围的间距

java - 内存与性能,哪个最好?

java - 当我们使用 Bitmap 时内存不足

c++ - 从 Mac 为 WIndows、Linux 交叉编译 C++/QT

c++ - QVector.push_back 错误

c++ - Qt : Pass parameter to receiving dropEvent 中的拖放问题

matlab - 删除切片中的小值

c# - 在图片框控件中显示后处理位图