我有Qt Quick Controls 2应用程序。在main.qml中我除了滚动视图中的其他东西之外还有:
Rectangle {
id: graph
width: mainArea.width / 3 - 14;
height: mainArea.height - 20;
ScrollView{
anchors.fill: parent;
Canvas {
id:canvasGraph;
width: graph.width;
height: graph.height;
property bool paintB: false;
property string colorRect: "#FFFF40";
property string name: "ELF header";
property int paintX: 0;
property int paintY: 0;
property int widthP: 160;
property int heightP: 30;
property int textX: (paintX + (widthP / 2)) - 15/*func return int length of text*/;
property int textY: (paintY + (heightP / 2)) + 3;
onPaint:{
if (paintB){
var ctx = canvasGraph.getContext('2d');
ctx.beginPath();
ctx.font = "normal 12px serif";
ctx.fillStyle = colorRect;
ctx.strokeRect(paintX, paintY, widthP, heightP);
ctx.fillRect(paintX, paintY, widthP, heightP);
ctx.strokeText("ELF header", textX, textY);
ctx.closePath();
ctx.save();
}
}
MouseArea{
id: canvasArea;
anchors.fill: parent;
onPressed: {
paint(mouseX,mouseY,"aaa",1);
}
}
}
}
}
起初我尝试通过js函数绘制到画布,这里:
function paint(x, y, name, type) {
canvasGraph.paintB = true;
canvasGraph.paintX = x;
canvasGraph.paintY = y;
canvasGraph.requestPaint();
}
通过在画布上按鼠标来调用此功能。它工作得很好,它逐个绘制矩形。但只有一个问题是,在调整应用程序窗口大小后,除了最后一个之外的所有矩形都会丢失。但这不是主要问题,因为它有效,而这个问题我以后可以解决。
对于绘制图表,我需要C ++库(ELFIO,用于读取ELF文件)。所以在main.cpp中我有两个对象。首先允许我从某些C ++类的main.qml函数调用。第二个允许我从C ++调用js函数。这是main.cpp:
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QScopedPointer<elfFile> elfFileObj(new elfFile);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
engine.rootContext()->setContextProperty("elfFileObj", elfFileObj.data()); //this is for calling c++ from qml
QObject *rof = engine.rootObjects().first();
elfFileObj.data()->rofS = rof; //this one is for calling js func from c++
return app.exec();
如何看,读取ELF文件是从对象 elfFileObj 进行管理,其中是保存加载的ELF文件的公共变量和保存对象的变量 rofS .qml到js函数。
在 elfFileObj 是 Q_INVOKABLE int loadELF(QString fileName); 其中Q_INVOKABLE是宏,这确保了这个函数可以从qml文件调用。功能:
int elfFile::loadELF(QString fileName)
{
string fileNameReal = (fileName).toStdString().substr(7);
if (!reader.load(fileNameReal.c_str())){
return -1;
}
QVariant x(30);
QVariant y(10);
QVariant name("ELF header");
QVariant type(1);
QMetaObject::invokeMethod(rofS, "paint", Q_ARG(QVariant,x), Q_ARG(QVariant,y), Q_ARG(QVariant,name), Q_ARG(QVariant,type));
y = QVariant(40);
QMetaObject::invokeMethod(rofS, "paint", Q_ARG(QVariant,x), Q_ARG(QVariant,y), Q_ARG(QVariant,name), Q_ARG(QVariant,type));
}
我尝试逐个绘制两个矩形。 QMetaObject :: invokeMethod 应该调用js函数,它们在(x,y)上绘制矩形。其他args在这个时刻无法使用。
主要问题:它在画布上绘制矩形,但在每次调用invokeMethod之后都会清除画布。因此在画布上始终只保留最后一个矩形。
有人知道,如何保存画布的实际状态?谢谢你的帮助。 它不是很好的代码,但它是我第一次使用qml。
答案 0 :(得分:0)
画布作为命令式绘图API,只有一个像素数据的哑缓冲区。绘制调用完成后,它没有矩形或其他任何对象的概念。因此,您负责通过onPaint处理程序显示的所有内容。它不会将画布内容从一个帧清除到另一个帧(作为优化),但它会(必要时)在调整窗口大小时将其清除,因为它必须分配不同大小的缓冲区。
您可以在此处看到此行为:
import QtQuick 2.6
Canvas {
id: canvasGraph;
width: 500
height: 500
property int paintY: 10;
onPaint:{
var ctx = canvasGraph.getContext('2d');
ctx.beginPath();
ctx.font = "normal 12px serif";
ctx.fillStyle = "#ff0000";
ctx.strokeRect(10, paintY, 160, 30);
ctx.fillRect(10, paintY, 160, 30);
ctx.closePath();
ctx.save();
}
Timer {
interval: 16
running: true
repeat: true
onTriggered: {
canvasGraph.requestPaint();
canvasGraph.paintY += 10
if (canvasGraph.paintY > canvasGraph.height)
canvasGraph.paintY = 10
}
}
}
尝试使用qmlscene运行此示例并调整窗口大小。您会注意到所有内容都会在调整大小时被清除,除了它绘制的一个矩形。
所以,如果你想要保留所有的矩形,那么你每次都需要在onPaint处理程序中绘制它们(并使用clearRect或其他一些方法来填充背景以消除那些没有的东西。如果你正在移动东西或使它们变得不可见,那就不再属于那里了。
另一方面,我不能直接解释为什么invokeMethod会导致它清除,因为你还没有真正提供足够的代码。它可能是它调整画布大小(导致缓冲区重新分配,并被清除)。无论哪种方式,鉴于上述情况,我都说它并非全部相关。
毕竟,虽然我没有完全了解你所做的事情,但我建议Canvas可能不是做你想做的最好的工具。你可能想要查看QQuickPaintedItem,或者(更好的是)使用定制其他QQuickItems(或QSGNodes)的自定义QQuickItem来编写场景。 Canvas(和QQuickPaintedItem)虽然易于使用,但性能并不高。
答案 1 :(得分:0)
我没有解决这个问题。我只是停止使用QML并返回使用Qt。它帮助了我。