QtQuick、动态图像和 C++
我是 Qt 新手,根据我在 qt-project.org 等地;QtQuick 似乎是一个有吸引力的选择,因为它能够在基于指针和触摸的设备上工作.我的问题是让它与 c++ 一起工作.
I'm new to Qt, and from what I've read on qt-project.org and other places; QtQuick seems like an attractive option because of its ability to work on both pointer and touch based devices. My problem is getting it to work well with c++.
我决定写一个康威生命游戏的变体,作为Hello World"之后的下一步.对于如何将板"――一个 [height][width][bytes-per-pixel] 字符数组――集成到场景图中,我完全感到困惑.
I decided to write a variant of Conway's Game of Life as a next step after "Hello World". I am thoroughly mystified as to how to get the "board" -- a [height][width][bytes-per-pixel] array of char -- integrated into the scene graph.
基本上,该过程是LifeBoard"迭代其规则并更新 char*/image.我有这个简单的 QML:
Basically, the process is that the "LifeBoard" iterates through its rules and updates the char*/image. I've got this simple QML:
:::QML
ApplicationWindow {
id: life_app_window
visible: true
title: qsTr("Life")
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit();
}
}
}
toolBar: ToolBar {
id: lifeToolBar;
ToolButton {
id: toolButtonQuit
text: qsTr("Quit")
onClicked: Qt.quit()
}
ToolButton {
id: toolButtonStop
text: qsTr("Stop")
enabled: false
//onClicked:
}
ToolButton {
id: toolButtonStart
text: qsTr("Start")
enabled: true
//onClicked: //Start life.
}
ToolButton {
id: toolButtonReset
text: qsTr("Stop")
// onClicked: //Reset life.
}
}
Flow {
id: flow1
anchors.fill: parent
//*****
// WHAT GOES HERE
//*****
}
statusBar: StatusBar {
enabled: false
Text {
// Get me from number of iterations
text: qsTr("Iterations.")
}
}
}
我希望图像来自一个具有类似这样的 api 的类:
I want to image to come from a class with a api kinda like this:
class Life {
public:
QImage getImage() {}
// Or
char* getPixels(int h, int w, QImage::Format_ARGB8888) {}
}
我没有任何线索,而且花费数小时阅读教程也无济于事.如何将 C++ 中的 char* 图像链接到 ???在 QML 中,以便 QML 可以启动/停止Life"循环,以便Life"循环并更新 char 数组并通知 QML 重绘它?
I have no clue, and hours wading through tutorials did not help. How does one link a char* image in c++ to a ??? in QML so that the QML can start/stop the "Life" loop and so that the "Life" loop and update the char array and notify QML to redraw it?
注意:我已经根据 这里的信息查看了 QQuickImageProvider 的子类化一个>.这种方法的问题是我看不到如何让 c++ 驱动"屏幕上的图像.我希望将控制权从 QML 传递给 c++,并让 c++ 告诉 QML 何时使用更改后的图像更新显示.这种方法有解决方案吗?或者完全是另一种方法.
Note: I've looked at subclassing QQuickImageProvider based on the info here. The problem with this approach is that I cannot see how to let c++ "drive" the on screen image. I wish to pass control from QML to c++ and let c++ tell QML when to update the display with the changed image. Is there a solution with this approach? Or another approach entirely.
推荐答案
第一种方法是创建一个 Rectangle 用于 QML 中的每个游戏像素,这对于 8x8 棋盘来说可能很有趣,但对于 100x100 棋盘则不合适,因为您需要为每个像素手动编写 QML 代码.
First way to do that would be creating a Rectangle for each game pixel in QML, which might be fancy for a 8x8 board, but not for a 100x100 board, since you need to write the QML code manually for each pixel.
因此,我会选择用 C++ 创建并暴露给 QML 的图像.您可以通过 图像提供程序 调用它们以允许异步加载.让Life
只做逻辑.
Thus I'd go for images created in C++ and exposed to QML. You call them via an image provider to allow asynchronous loading. Let Life
do the logic only.
图像是从 QML 中调用的,如下所示:
The image is called from QML like this:
Image {
id: board
source: "image://gameoflife/board"
height: 400
width: 400
}
现在gameoflife
是图片提供者的名字,board
就是所谓的id
,以后可以使用.
Now gameoflife
is the name of the image provider and board
the so-called id
you can use later.
在你的main.cpp
LifeImageProvider *lifeIP = new LifeImageProvider(life);
engine.addImageProvider("gameoflife", lifeIP);
其中 engine
是您的主要 QQmlApplicationEngine
并且 life
是您的 Life
游戏引擎的一个实例.
where engine
is your main QQmlApplicationEngine
and life
an instance of your Life
game engine.
LifeImageProvider
是您创建像素数据的类.以某种方式开始
LifeImageProvider
is your class to create pixeldata. Starts somehow like
class LifeImageProvider : public QQuickImageProvider
{
public:
LifeImageProvider(Life *myLifeEngine);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
private:
Life *myLifeEngine_;
};
重要的方法是从QML调用的requestPixmap.你需要实现它.
The important method is requestPixmap, which is called from QML. You need to implement it.
要在 Life
发送 stateChanged()
信号时刷新游戏板,请将 life
作为全局对象公开给 QML:
To refresh the game board when Life
sends a stateChanged()
signal, expose life
as a global object to QML:
context->setContextProperty("life", &life);
您可以将信号绑定到 QML
You can bind the signal to QML
Image {
id: board
source: "image://gameoflife/board"
height: 400
width: 400
}
Connections {
target: life
onStateChanged: {
board.source = "image://gameoflife/board?" + Math.random()
// change URL to refresh image. Add random URL part to avoid caching
}
}
相关文章