在 QML 中显示和刷新图像

Display and refresh an image in QML

本文关键字:刷新 图像 显示 QML      更新时间:2023-10-16

我不明白如何使用QQuickPaintedItem类(或者另一种方法?

我的程序目前正在使用 QImage 和 ImageProvider 显示它,它可以工作但随机崩溃,所以我想尝试另一种方法。

此外,每次传输新帧时都应刷新图像。

我从uchar原始数据中获取信息,但我看不到如何从原始数据中绘制。

此外,新的原始数据大约以 60 fps 的速度出现,因此 QML 需要以这种速度刷新图像。

编辑:

代码的其他部分:

我的班级是:

class StreamPainter : public QQuickPaintedItem
{
    Q_OBJECT
public:
    StreamPainter(QQuickItem *p = 0):QQuickPaintedItem(p){}
    ~StreamPainter();
    void paint(QPainter *painter){painter->drawImage(QPoint(0, 0), _streamImage);}

public slots:
    void onImageAvailable(QImage image) {
        _streamImage = image;
        update();
private:
    QImage _streamImage;
};

在主要:

对于无效的属性名称,这是由于导入了 StreamPainter 1.0,似乎它不喜欢这个名称,因为它被合并了,我已将其更改为 myModule,错误消失了。

qmlRegisterType<StreamPainter>("myModule", 1, 0, "StreamPainter");

创建对象和线程:

streamImage = new StreamPainter();
myPipeThread = new PipeThread(streamImage);

线程构造函数:

PipeThread::PipeThread(StreamPainter* spvideostr)
:QThread(),
 _namedPipe(INVALID_HANDLE_VALUE),
 _spvideostr(spvideostr),
 _abort(false),
 _rawData(NULL)
{
    ...
}

线程类,我添加了:

signals:
    void imageAvailable(QImage image);

然后在我的线程中,我进行连接,同时我创建 QImage 并发出信号:

connect(this, SIGNAL(imageAvailable(QImage)), _spvideostr, SLOT(onImageAvailable(QImage)));
while(...)
    QImage clImage(_rawData, IMG_WIDTH, IMG_HEIGHT,     QImage::Format_Indexed8);
    emit imageAvailable(clImage);

QML :

import QtQuick 2.0
import MyModule 1.0
StreamPainter {
    width : 100 
    height : 100 

就我而言,我在 QML 中使用组件中的函数刷新图像,如下所示:

Image {
                id: imageLogo
                cache: false
                anchors.fill: parent
                //anchors.leftMargin: 20
                Layout.preferredWidth: Math.round(parent.width / 1.5)
                Layout.preferredHeight: Math.round(parent.height * 2)
                function reloadImage() {
                    var oldSource = source
                    source = ""
                    source = oldSource
                }//function to refresh the source
            }

然后我只在你想重新加载图像的地方调用这个函数

imageLogo.reloadImage()

这很简单,您所要做的就是在paint()方法中绘制图像:

void paint(QPainter *painter) {
    painter->drawImage(QPoint(0, 0), yourImage);
}

然后在每次更改时拨打update() yourImage

不要绘制原始数据,使用正确的格式从中创建QImage并绘制它。您可以使用静态方法QImage fromData(const uchar *data, int size, const char *format = Q_NULLPTR) 。由于QImage是隐式共享对象,因此每次获取新数据时都可以有效地yourImage = QImage::fromData(...)然后update()

编辑:

您应该在 QML 中创建对象。另外,看到如何使用线程,请记住 UI 元素只能从主线程访问。这意味着您无法执行此操作:

_spvideostr->setStreamImage(clImage);
_spvideostr->update();

当您从另一个线程访问 UI 对象时。相反,您应该使用带有排队连接的信号和插槽,通过该连接传递映像,然后从StreamPainter插槽设置映像和调用update()

你不需要那个:

Q_PROPERTY(QImage streamImage READ streamImage WRITE setStreamImage NOTIFY streamImageChanged)

只能从该类访问此映像。所以你也不需要这些:

QImage streamImage();
void setStreamImage(QImage clImage);
signals:
    void streamImageChanged(QImage Image);

您需要的是:

public slots:
    void onImageAvaiable(QImage image) { ...set image and call update }

PipeThread您需要一个信号void imageAvaiable(QImage),将imageAvaiable连接到onImageAvaiable并发出图像:

QImage clImage(_rawData, IMG_WIDTH, IMG_HEIGHT, QImage::Format_Indexed8);
emit imageAvaiable(clImage);

我通过将Imagesource 属性绑定到我在任意查询字符串上附加的 url 来解决刷新 QML 中的图像,并且每次检索值时都使用自动递增计数器简单地更改图像位置附加部分中的值。

粗略地说,像这样(从 C 端):

QString imageURL()
{
    static const QString QUERY_STRING_KEY( "?refresh=" );
    static ushort imageRefreshCounter( 0 );
    return imageUrl_ +
        QUERY_STRING_KEY + QString::number( ++imageRefreshCounter );
}

当发出某些信号时,此功能将通过Q_PROPERTY隐式触发(例如 emit imageChanged(); ),这将触发 QML 绑定刷新。

这样做,就不需要更改实际映像的名称,也无需在 QML 端进行清除和重置源属性的游戏。

注意:根据您希望如何在自己的项目中编写此内容,您可以选择进一步抽象它,使用文字 QUrl,并调用其 setQuery 方法。 我在这里用原始字符串展示这一点,只是为了让它更简单/直接一点。