我是Qt的新手,也是我在qt-project.org和其他地方读过的内容。 QtQuick似乎是一个很有吸引力的选择,因为它能够在指针和触摸设备上工作。我的问题是让它与c ++一起使用。
我决定在“Hello World”之后编写一个Conway的生命游戏变体作为下一步。关于如何获得“板” - 一个[高度] [宽度] [字节每像素] char数组 - 我已经完全神秘化了 - 集成到场景图中。
基本上,过程是“LifeBoard”遍历其规则并更新char * / image。我有这个简单的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类:
class Life {
public:
QImage getImage() {}
// Or
char* getPixels(int h, int w, QImage::Format_ARGB8888) {}
}
我没有任何线索,花时间浏览教程并没有帮助。如何将c ++中的char *图像链接到???在QML中,QML可以启动/停止“Life”循环,以便“Life”循环并更新char数组并通知QML重绘它?
注意:我已经根据信息here查看了对QQuickImageProvider的子类化。这种方法的问题在于我无法看到如何让c ++“驱动”屏幕上的图像。我希望将控制从QML传递给c ++,让c ++告诉QML何时用更改的图像更新显示。这种方法有解决方案吗?或完全是另一种方法。
答案 0 :(得分:7)
这样做的第一种方法是为QML中的每个游戏像素创建一个Rectangle,这对于8x8板可能很有用,但对于100x100板则不行,因为你需要手动编写QML代码每个像素。
因此,我会选择用C ++创建并暴露给QML的图像。您可以通过image provider调用它们以允许异步加载。让Life
只做逻辑。
从QML中调用图像,如下所示:
Image {
id: board
source: "image://gameoflife/board"
height: 400
width: 400
}
现在gameoflife
是图片提供者的名称,board
是您稍后可以使用的所谓id
。
在gameoflife
main.cpp
LifeImageProvider *lifeIP = new LifeImageProvider(life);
engine.addImageProvider("gameoflife", lifeIP);
其中engine
是您的主QQmlApplicationEngine
和life
Life
游戏引擎的实例。
LifeImageProvider
是您创建pixeldata的类。以某种方式开始像
class LifeImageProvider : public QQuickImageProvider
{
public:
LifeImageProvider(Life *myLifeEngine);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
private:
Life *myLifeEngine_;
};
重要的方法是requestPixmap,它是从QML调用的。你需要实现它。
要在Life
发送stateChanged()
信号时刷新游戏板,请将life
公开为QML的全局对象:
context->setContextProperty("life", &life);
您可以将信号绑定到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
}
}
答案 1 :(得分:1)
只是为了好玩,而且冒着完全切向回答的风险,这里是一个完全用QML实现的GameOfLife,只需将它放在一个.qml文件中并用qmlscene运行它。在Qt 5.3.0上运行,并且在一个旧的Core 2 Duo lappy上以令人惊讶的速度(对我而言)运行。我确信它永远不会像基于C ++ QQuickImageProvider的解决方案那样快速/高效,但它确实说明了在QML中做很多事情而不诉诸C ++。
import QtQuick 2.2
Rectangle {
id: main
width: 640
height: 640
color: '#000088'
Timer {
interval: 1000/60
running: true
repeat: true
onTriggered: {advance();display();}
}
Component {
id: cellComponent
Rectangle {
objectName: 'cell'
property int row: 0
property int col: 0
x: main.width/2+width*col
y: main.height/2+height*row
width: 5
height: 5
radius: 2
smooth: true
color: '#ffcc00'
}
}
property var cells: null
Component.onCompleted: {
cells=[[-1, 0],[-1, 1],[ 0,-1],[ 0, 0],[ 1, 0]];
display();
}
function display() {
// Just completely regenerate display field each frame
// TODO: might be nicer to do differential updates, would allow birth/death animations
// Nuke all previously displayed cells
for (var i=0;i<children.length;i++) {
if (children[i].objectName=='cell') {
children[i].destroy();
}
}
// Show current set of cells
for (var i=0;i<cells.length;i++) {
var c=cellComponent.createObject(
main,
{'row':cells[i][0],'col':cells[i][1]}
);
}
}
function advance() {
// Build a hash of the currently alive cells and a neighbour count (includes self)
var a=new Object;
var n=new Object;
for (var i=0;i<cells.length;i++) {
var p=cells[i]
var r=p[0];
var c=p[1];
if (!(r in a)) a[r]=new Object;
a[r][c]=1;
for (var dr=r-1;dr<=r+1;dr++) {
for (var dc=c-1;dc<=c+1;dc++) {
if (!(dr in n)) n[dr]=new Object;
if (!(dc in n[dr])) n[dr][dc]=0;
n[dr][dc]+=1;
}
}
}
// For all live cells, assess viability
var kill=[];
var stay=[];
for (var r in a) {
for (var c in a[r]) {
if (n[r][c]-1<2 || n[r][c]-1>3)
kill.push([Number(r),Number(c)]);
else
stay.push([Number(r),Number(c)]);
}
}
// For neighbours of live cells, assess potential for births
var born=[];
for (var r in n) {
for (var c in n[r]) {
if (!((r in a) && (c in a[r]))) {
if (n[r][c]==3)
born.push([Number(r),Number(c)]);
}
}
}
cells=stay.concat(born)
}
}
对于使用GLSL(通过递归QML ShaderEffect)的纯QML版本来计算GPU see here上的生命游戏规则。