Qt/QML:将 QImage 从 C++ 发送到 QML 并在 GUI 上显示 QImage
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20691414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Qt/QML : Send QImage From C++ to QML and Display The QImage On GUI
提问by trianta2
I created a class Publisher
which periodically emits a QImage
object.
我创建了一个Publisher
定期发出QImage
对象的类。
However I'm having a tough time drawing the QImage
to a QML element. It appears that the Image
and Canvas
QML components require a QUrl
instead of a QImage
, but I'm not sure how to convert my QImage
to a QUrl
. Edit4: When I say QUrl, I don't mean I'm trying to convert an image to a URL. That's nonsense. I mean I want to generate a reference to this image, which is not on disk, and the data type that QML components are asking for is a URL.
但是,我很难将 绘制QImage
到 QML 元素。似乎 theImage
和Canvas
QML 组件需要 aQUrl
而不是 a QImage
,但我不确定如何将 my 转换QImage
为QUrl
. Edit4:当我说 QUrl 时,我并不是说我正在尝试将图像转换为 URL。那是胡说八道。我的意思是我想生成对这个图像的引用,它不在磁盘上,而 QML 组件要求的数据类型是一个 URL。
I've done some research and found that QQuickImageProvider
provides a solution, but I haven't found any documentation explaining how to convert my QImage
signal to a QUrl
that I can use for drawing. Any example code or reference documentation would be appreciated.
我做了一些研究,发现它QQuickImageProvider
提供了一个解决方案,但我没有找到任何文档来解释如何将我的QImage
信号转换为QUrl
我可以用于绘图的信号。任何示例代码或参考文档将不胜感激。
Thanks for your help!
谢谢你的帮助!
Edit1:
编辑1:
I've taken a look here: http://qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.htmland I do not see how I pass a QImage to the quick image provider and from it create a QUrl.
我在这里看了一下:http: //qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.html,我没有看到如何将 QImage 传递给快速图像提供程序并从中创建一个 QUrl .
Edit2. Here is the header. The implementation should not be important.
编辑2。这是标题。实施应该不重要。
class Publisher
{
Q_OBJECT
public:
Publisher(QObject* parent = 0);
virtual ~Publisher(void);
Q_SIGNALS:
void newImage(const QImage& newImage);
};
Edit 3. Here is my QML code, but I don't know how to draw my QImage, so this code is kind of meaningless.
编辑 3. 这是我的 QML 代码,但我不知道如何绘制我的 QImage,所以这段代码毫无意义。
my main.cpp file:
我的 main.cpp 文件:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Publisher>("Components", 1, 0, "Publisher");
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/QQuickViewExample/main.qml"));
viewer.showExpanded();
return app.exec();
}
my main.qml file:
我的 main.qml 文件:
import QtQuick 2.0
import Components 1.0
Rectangle {
id : testRect
width: 360
height: 360
Image{
anchors.fill: parent
id: myImage
Publisher {
id: myPub
onNewImage: {
myImage.source = newImage; #I know this doesnt work, it needs a QUrl and not a QImage
}
}
}
}
回答by peppe
In other words, you have a class emitting a signal carrying a QImage and want to update an item in QML with that image? There are various solutions, none of which involves "converting a QImage to a QUrl" (whatever that means, surely you don't need to get a data
URL carrying your image data...)
换句话说,您有一个类发出携带 QImage 的信号,并想用该图像更新 QML 中的项目?有多种解决方案,其中没有一个涉及“将 QImage 转换为 QUrl”(无论这意味着什么,您肯定不需要获取data
带有图像数据的URL...)
Use an image provider
使用图像提供程序
This means you can use a plain Image
item in your QML files.
这意味着您可以Image
在 QML 文件中使用普通项目。
- Create a
QQuickImageProvider
subclass; give it aQImage
member (the image to provider), overriderequestImage
to provide that image (the actualid
requested does not really matter, see below), and a slot that receives aQImage
and updates the member. - Connect your
Publisher
signal to your provider's slot - Install the provider into the QML engine via
QQmlEngine::addImageProvider
(seeQQuickView::engine
); again theid
does not really matter, just use a sensible one In QML, just use a plain
Image
element with a source like thisImage { id: myImage source: "image://providerIdPassedToAddImageProvider/foobar" }
foobar
will be passed to your provider, but again, it doesn't really matter.We're almost there, we now only need a way to pushthe image updates to the QML world (otherwise Image will never know when to update itself). See my answer herefor how to do that with a
Connections
element and a bit of JS.Note that in general you don't need to make
Publisher
a QML type, you just need to create oneinstance in C++ and expose it to the QML world viaQQmlContext::setContextProperty
.
- 创建
QQuickImageProvider
子类;给它一个QImage
成员(提供者的图像),覆盖requestImage
以提供该图像(实际id
请求并不重要,见下文),以及一个接收 aQImage
并更新成员的插槽。 - 将您的
Publisher
信号连接到您的提供商的插槽 - 通过
QQmlEngine::addImageProvider
(请参阅QQuickView::engine
)将提供程序安装到 QML 引擎中;再次这id
并不重要,只需使用明智的 在 QML 中,只需使用
Image
带有这样的源的普通元素Image { id: myImage source: "image://providerIdPassedToAddImageProvider/foobar" }
foobar
将传递给您的提供者,但同样,这并不重要。我们快到了,我们现在只需要一种将图像更新推送到 QML 世界的方法(否则图像将永远不知道何时更新自己)。请参阅我的答案,了解如何使用
Connections
元素和一些 JS来做到这一点。请注意,通常您不需要创建
Publisher
QML 类型,您只需要在 C++ 中创建一个实例并通过QQmlContext::setContextProperty
.
Use a custom Qt Quick 2 Item
使用自定义 Qt Quick 2 项目
QQuickPaintedItem
is probably the most convenient for the job as it offers a paint
method taking a QPainter
. Hence the big plan is
QQuickPaintedItem
可能是最方便的工作,因为它提供了paint
一种采用QPainter
. 因此,大计划是
- Subclass
QQuickPaintedItem
: the subclass stores theQImage
to be painted and has a slot that sets the new QImage. Also itspaint
implementation simply paints the image usingQPainter::drawImage
. - Expose the subclass to the QML world via
qmlRegisterType
(so that you can use it in QML) Figure out a way to connect the signal carrying the new image to the items' slot.
This might be the tricky part.
To perform the connection in C++ you need a way to figure out that the item has been created (and get a pointer to it); usually one does this by means of assigning the
objectName
property to some value, then usingfindChild
on the root object (as returned byQQuickView::rootObject()
) to get a pointer to the item itself. Then you can useconnect
as usual.Or, could instead perform the connection in QML, just like above, via a
Connections
element on the publisher C++ object exposed to the QML world:MyItem { id: myItem } Connections { target: thePublisherObjectExposedFromC++ onNewImage: myItem.setImage(image) }
This has the advantage of working no matter when you create the MyItem instance; but I'm not 100% sure it will work because I'm not sure you can handle the
QImage
type in QML.
- 子类
QQuickPaintedItem
:子类存储QImage
要绘制的对象,并有一个用于设置新 QImage 的插槽。此外,它的paint
实现只是使用QPainter::drawImage
. - 通过将子类暴露给 QML 世界
qmlRegisterType
(以便您可以在 QML 中使用它) 想办法将携带新图像的信号连接到物品的插槽。
这可能是棘手的部分。
要在 C++ 中执行连接,您需要一种方法来确定该项目已被创建(并获得指向它的指针);通常通过将
objectName
属性分配给某个值,然后使用findChild
根对象(由 返回QQuickView::rootObject()
)来获取指向项目本身的指针来实现这一点。然后就可以connect
照常使用了。或者,可以改为在 QML 中执行连接,就像上面一样,通过
Connections
向 QML 世界公开的发布者 C++ 对象上的元素:MyItem { id: myItem } Connections { target: thePublisherObjectExposedFromC++ onNewImage: myItem.setImage(image) }
无论您何时创建 MyItem 实例,这都有其优势;但我不是 100% 确定它会起作用,因为我不确定您是否可以处理
QImage
QML 中的类型。
回答by timday
When I've had image-producing C++ classes I've wanted to embed in QML, I've always done it by making the C++ class a subclass of QDeclarativeItem
(there'll be a new QtQuick 2.0 equivalent of course), overriding the paint method with the appropriate drawing code, which maybe as simple as
当我拥有想要嵌入 QML 的图像生成 C++ 类时,我总是通过使 C++ 类成为QDeclarativeItem
(当然会有一个新的 QtQuick 2.0 等效项)的子类来完成它,覆盖绘制具有适当绘图代码的方法,这可能就像
void MyItem::paint(QPainter* painter,const QStyleOptionGraphicsItem*,QWidget*) {
painter->drawImage(QPointF(0.0f,0.0f),_image);
}
if you have a QImage of the right size already... and Job Done. For animation, just ping update() when there's something new to draw.
如果你已经有一个合适大小的 QImage ......并且工作完成了。对于动画,只需在有新内容要绘制时 ping update() 即可。
回答by Doug Rogers
Use QQuickItem. There is a Qt example that does this.
使用 QQuickItem。有一个 Qt 示例可以做到这一点。
C:\Qt\Examples\Qt-5.14.1\quick\scenegraph\threadedanimation
C:\Qt\Examples\Qt-5.14.1\quick\scenegraph\threadedanimation
You make a class derived from QQuickItem and register it with qmlRegisterType. Provide the override function 'updatePaintNode' in your class. In the example, the class is 'Spinner'
您创建一个从 QQuickItem 派生的类并使用 qmlRegisterType 注册它。在您的课程中提供覆盖函数“updatePaintNode”。在示例中,类是“Spinner”
In updatePaintNode:
在 updatePaintNode 中:
Create a node class derived from QObject and QSGTransformNode
创建从 QObject 和 QSGTransformNode 派生的节点类
In the node class constructor:
在节点类构造函数中:
Convert your Qimage to an QSGTexture with createTextureFromImage.
使用 createTextureFromImage 将 Qimage 转换为 QSGTexture。
Create QSGSimpleTextureNode, set QSGTexture using setTexture
创建 QSGSimpleTextureNode,使用 setTexture 设置 QSGTexture
appendChildNode with QSGSimpleTextureNode
带有 QSGSimpleTextureNode 的 appendChildNode
In QML add
在 QML 中添加
import Spinner 1.0
and
和
Spinner {
anchors.centerIn: parent
anchors.horizontalCenterOffset: 80
spinning: true
}