QML Shape:如何强制数据 属性 以干净的方式更新?
QML Shape: How can I force data property to update in a clean way?
我正在尝试创建一个 window,我可以在其中绘制三角形并使用 Shape{} 删除其中的任何一个。在下面的示例中,我可以绘制两种类型的三角形:
- 向上三角形:绿色且已填充
- 向下三角形:黄色且未填充
基本上,我选择三角形的类型(右下角有一个按钮)然后我点击 window 上的任意位置来获得一个三角形。
一旦我点击一个三角形,它就会被动态创建并存储在 属性 triangleList 中。然后我调用函数 shape.update() 来更新形状的 data 属性 。这部分效果很好。
这里是我在 Shape 中使用的函数更新(因为数据是一个列表,我必须重新分配到一个新列表。):
function update()
{
data = [];
var d = [];
for (var i = 0; i < canvas.triangleList.length; i++)
{
d.push( canvas.triangleList[i] );
}
data = d;
}
当我尝试删除三角形时出现问题。在我的示例中,我可以删除第一个、最后一个或所有三角形。当我删除一个三角形时,首先我删除 triangleList 中的值,然后我再次调用 shape.update()。当我删除所有三角形或最后一个三角形时,它会起作用。
但是,当我尝试删除第一个三角形时,数据不会更新它的对象,即使我给它一个新列表。事实上,它总是删除最后一个三角形。下面是一个例子:
data 属性 知道少了一个三角形,但它不会更新其他三角形。我找到的唯一解决方案是更改 属性 然后返回到原始值。这样,它强制更新数据。
但是我必须为 每个可能不同的 属性 这样做(颜色和位置)。因此,我的 update() 函数看起来像这样:
for (var i = 0; i < canvas.triangleList.length; i++)
{
d.push( canvas.triangleList[i] );
////// Change properties one by one to force the refresh
// Force path redraw. Otherwise only the last path can be deleted
d[i].startX++;d[i].startX--;
// Force line color update
d[i].strokeColor = "red"
d[i].strokeColor = d[i].isUp ? "green" : "yellow";
// Force fill color update
d[i].fillColor = "red";
d[i].fillColor = d[i].isUp ? "green" : "transparent";
data = d;
}
我邀请您评论 in/out 这些行以查看不同之处。
我可以使用这个技巧来强制更新,但我的实际代码确实比这个示例大,而且我使用了绑定。
所以我的问题是:有没有办法强制更新而不必更改每个 属性?
如果你想测试它,这里有完整的代码:
import QtQuick 2.9;
import QtQuick.Controls 2.2;
import QtQuick.Shapes 1.0;
ApplicationWindow {
visible: true; width: 640; height: 480;
Rectangle {
id: canvas;
anchors.fill: parent;
color: "black";
property var triangleList: [];
property bool triangleUp: true;
MouseArea {
anchors.fill: parent;
onClicked: {
var triangle = componentTriangle.createObject(componentTriangle, {
"isUp" : canvas.triangleUp,
"startX" : mouse.x,
"startY" : mouse.y,
}, canvas);
canvas.triangleList.push(triangle);
shape.update();
}
} // MouseArea
Shape {
id: shape;
anchors.fill: parent;
function update()
{
data = [];
var d = [];
for (var i = 0; i < canvas.triangleList.length; i++)
{
d.push( canvas.triangleList[i] );
///////////// HOW TO AVOID THE PART BELOW? /////////////
////// Change properties one by one to force the refresh
// Force path redraw. Otherwise only the last path can be deleted
d[i].startX++;d[i].startX--;
// Force line color update
d[i].strokeColor = "red"
d[i].strokeColor = d[i].isUp ? "green" : "yellow";
// Force fill color update
d[i].fillColor = "red";
d[i].fillColor = d[i].isUp ? "green" : "transparent";
//////////////////////////////////////////////////////
}
data = d;
// I make sure data has at least one path to ensure the refresh
if (data.length == 0)
data.push(Qt.createQmlObject('import QtQuick 2.9; import QtQuick.Shapes 1.0; ShapePath {startX:0;startY:0;}', canvas,
"force_refresh"));
}
} // Shape
} // Rectangle
//////////// Buttons to handle the triangles
Column {
anchors.bottom: parent.bottom;
anchors.right: parent.right;
Button {
text: canvas.triangleUp? "Draw triangleUp" : "Draw triangleDown";
onClicked: { canvas.triangleUp = !canvas.triangleUp; }
} // Button
Button {
text: "Clear first";
onClicked: {
canvas.triangleList[0].destroy();
canvas.triangleList.splice(0,1);
shape.update();
}
} // Button
Button {
text: "Clear last";
onClicked: {
canvas.triangleList[canvas.triangleList.length -1].destroy();
canvas.triangleList.splice(canvas.triangleList.length -1,1);
shape.update();
}
} // Button
Button {
text: "Clear all";
onClicked: {
for (var i = 0; i < canvas.triangleList.length; i++)
canvas.triangleList[i].destroy();
canvas.triangleList = [];
shape.update();
}
} // Button
}
//////////// Component to draw the triangle
Component {
id: componentTriangle;
ShapePath {
property bool isUp;
property real offsetX: isUp? -20 : 20;
property real offsetY: isUp? -30 : 30;
strokeColor: isUp ? "green" : "yellow";
strokeWidth: 3;
fillColor: isUp ? "green" : "transparent";
PathLine { x: startX - offsetX; y: startY - offsetY }
PathLine { x: startX + offsetX; y: startY - offsetY }
PathLine { x: startX; y: startY }
} // ShapePath
}
}
非常感谢您的帮助,有什么不明白的可以随时问我。
祝你有愉快的一天!
如果您要处理许多物品(形状),建议使用带有模型的中继器。中继器负责根据模型的信息显示物品,移除物品只需要从模型中移除物品即可。
main.qml
import QtQuick 2.9;
import QtQuick.Controls 2.2;
import QtQuick.Shapes 1.0;
ApplicationWindow {
visible: true; width: 640; height: 480;
QtObject{
id: internals
property bool triangleUp: true;
}
ListModel{
id: datamodel
}
Rectangle {
id: canvas;
anchors.fill: parent;
color: "black";
Repeater{
model: datamodel
Triangle{
x: model.x
y: model.y
isUp: model.isUp
}
}
MouseArea{
anchors.fill: parent
onClicked: datamodel.append({"x": mouse.x, "y": mouse.y, "isUp": internals.triangleUp})
}
}
Column {
anchors.bottom: parent.bottom;
anchors.right: parent.right;
Button {
text: internals.triangleUp ? "Draw triangleUp" : "Draw triangleDown";
onClicked: internals.triangleUp = !internals.triangleUp;
} // Button
Button {
text: "Clear first";
onClicked: if(datamodel.count > 0) datamodel.remove(0)
} // Button
Button {
text: "Clear last";
onClicked: if(datamodel.count > 0) datamodel.remove(datamodel.count - 1)
} // Button
Button {
text: "Clear all";
onClicked: datamodel.clear()
} // Button
}
}
Triangle.qml
import QtQuick 2.9;
import QtQuick.Shapes 1.0
Shape {
id: shape
property bool isUp: false
QtObject{
id: internals
property real offsetX: isUp? -20 : 20;
property real offsetY: isUp? -30 : 30;
}
ShapePath {
strokeWidth: 3;
strokeColor: isUp ? "green" : "yellow";
fillColor: isUp ? "green" : "transparent";
PathLine { x: -internals.offsetX ; y: -internals.offsetY }
PathLine { x: internals.offsetX; y: -internals.offsetY }
PathLine { x: 0; y: 0 }
}
}
我正在尝试创建一个 window,我可以在其中绘制三角形并使用 Shape{} 删除其中的任何一个。在下面的示例中,我可以绘制两种类型的三角形:
- 向上三角形:绿色且已填充
- 向下三角形:黄色且未填充
基本上,我选择三角形的类型(右下角有一个按钮)然后我点击 window 上的任意位置来获得一个三角形。
一旦我点击一个三角形,它就会被动态创建并存储在 属性 triangleList 中。然后我调用函数 shape.update() 来更新形状的 data 属性 。这部分效果很好。
这里是我在 Shape 中使用的函数更新(因为数据是一个列表,我必须重新分配到一个新列表。):
function update()
{
data = [];
var d = [];
for (var i = 0; i < canvas.triangleList.length; i++)
{
d.push( canvas.triangleList[i] );
}
data = d;
}
当我尝试删除三角形时出现问题。在我的示例中,我可以删除第一个、最后一个或所有三角形。当我删除一个三角形时,首先我删除 triangleList 中的值,然后我再次调用 shape.update()。当我删除所有三角形或最后一个三角形时,它会起作用。
但是,当我尝试删除第一个三角形时,数据不会更新它的对象,即使我给它一个新列表。事实上,它总是删除最后一个三角形。下面是一个例子:
data 属性 知道少了一个三角形,但它不会更新其他三角形。我找到的唯一解决方案是更改 属性 然后返回到原始值。这样,它强制更新数据。 但是我必须为 每个可能不同的 属性 这样做(颜色和位置)。因此,我的 update() 函数看起来像这样:
for (var i = 0; i < canvas.triangleList.length; i++)
{
d.push( canvas.triangleList[i] );
////// Change properties one by one to force the refresh
// Force path redraw. Otherwise only the last path can be deleted
d[i].startX++;d[i].startX--;
// Force line color update
d[i].strokeColor = "red"
d[i].strokeColor = d[i].isUp ? "green" : "yellow";
// Force fill color update
d[i].fillColor = "red";
d[i].fillColor = d[i].isUp ? "green" : "transparent";
data = d;
}
我邀请您评论 in/out 这些行以查看不同之处。 我可以使用这个技巧来强制更新,但我的实际代码确实比这个示例大,而且我使用了绑定。
所以我的问题是:有没有办法强制更新而不必更改每个 属性?
如果你想测试它,这里有完整的代码:
import QtQuick 2.9;
import QtQuick.Controls 2.2;
import QtQuick.Shapes 1.0;
ApplicationWindow {
visible: true; width: 640; height: 480;
Rectangle {
id: canvas;
anchors.fill: parent;
color: "black";
property var triangleList: [];
property bool triangleUp: true;
MouseArea {
anchors.fill: parent;
onClicked: {
var triangle = componentTriangle.createObject(componentTriangle, {
"isUp" : canvas.triangleUp,
"startX" : mouse.x,
"startY" : mouse.y,
}, canvas);
canvas.triangleList.push(triangle);
shape.update();
}
} // MouseArea
Shape {
id: shape;
anchors.fill: parent;
function update()
{
data = [];
var d = [];
for (var i = 0; i < canvas.triangleList.length; i++)
{
d.push( canvas.triangleList[i] );
///////////// HOW TO AVOID THE PART BELOW? /////////////
////// Change properties one by one to force the refresh
// Force path redraw. Otherwise only the last path can be deleted
d[i].startX++;d[i].startX--;
// Force line color update
d[i].strokeColor = "red"
d[i].strokeColor = d[i].isUp ? "green" : "yellow";
// Force fill color update
d[i].fillColor = "red";
d[i].fillColor = d[i].isUp ? "green" : "transparent";
//////////////////////////////////////////////////////
}
data = d;
// I make sure data has at least one path to ensure the refresh
if (data.length == 0)
data.push(Qt.createQmlObject('import QtQuick 2.9; import QtQuick.Shapes 1.0; ShapePath {startX:0;startY:0;}', canvas,
"force_refresh"));
}
} // Shape
} // Rectangle
//////////// Buttons to handle the triangles
Column {
anchors.bottom: parent.bottom;
anchors.right: parent.right;
Button {
text: canvas.triangleUp? "Draw triangleUp" : "Draw triangleDown";
onClicked: { canvas.triangleUp = !canvas.triangleUp; }
} // Button
Button {
text: "Clear first";
onClicked: {
canvas.triangleList[0].destroy();
canvas.triangleList.splice(0,1);
shape.update();
}
} // Button
Button {
text: "Clear last";
onClicked: {
canvas.triangleList[canvas.triangleList.length -1].destroy();
canvas.triangleList.splice(canvas.triangleList.length -1,1);
shape.update();
}
} // Button
Button {
text: "Clear all";
onClicked: {
for (var i = 0; i < canvas.triangleList.length; i++)
canvas.triangleList[i].destroy();
canvas.triangleList = [];
shape.update();
}
} // Button
}
//////////// Component to draw the triangle
Component {
id: componentTriangle;
ShapePath {
property bool isUp;
property real offsetX: isUp? -20 : 20;
property real offsetY: isUp? -30 : 30;
strokeColor: isUp ? "green" : "yellow";
strokeWidth: 3;
fillColor: isUp ? "green" : "transparent";
PathLine { x: startX - offsetX; y: startY - offsetY }
PathLine { x: startX + offsetX; y: startY - offsetY }
PathLine { x: startX; y: startY }
} // ShapePath
}
}
非常感谢您的帮助,有什么不明白的可以随时问我。
祝你有愉快的一天!
如果您要处理许多物品(形状),建议使用带有模型的中继器。中继器负责根据模型的信息显示物品,移除物品只需要从模型中移除物品即可。
main.qml
import QtQuick 2.9;
import QtQuick.Controls 2.2;
import QtQuick.Shapes 1.0;
ApplicationWindow {
visible: true; width: 640; height: 480;
QtObject{
id: internals
property bool triangleUp: true;
}
ListModel{
id: datamodel
}
Rectangle {
id: canvas;
anchors.fill: parent;
color: "black";
Repeater{
model: datamodel
Triangle{
x: model.x
y: model.y
isUp: model.isUp
}
}
MouseArea{
anchors.fill: parent
onClicked: datamodel.append({"x": mouse.x, "y": mouse.y, "isUp": internals.triangleUp})
}
}
Column {
anchors.bottom: parent.bottom;
anchors.right: parent.right;
Button {
text: internals.triangleUp ? "Draw triangleUp" : "Draw triangleDown";
onClicked: internals.triangleUp = !internals.triangleUp;
} // Button
Button {
text: "Clear first";
onClicked: if(datamodel.count > 0) datamodel.remove(0)
} // Button
Button {
text: "Clear last";
onClicked: if(datamodel.count > 0) datamodel.remove(datamodel.count - 1)
} // Button
Button {
text: "Clear all";
onClicked: datamodel.clear()
} // Button
}
}
Triangle.qml
import QtQuick 2.9;
import QtQuick.Shapes 1.0
Shape {
id: shape
property bool isUp: false
QtObject{
id: internals
property real offsetX: isUp? -20 : 20;
property real offsetY: isUp? -30 : 30;
}
ShapePath {
strokeWidth: 3;
strokeColor: isUp ? "green" : "yellow";
fillColor: isUp ? "green" : "transparent";
PathLine { x: -internals.offsetX ; y: -internals.offsetY }
PathLine { x: internals.offsetX; y: -internals.offsetY }
PathLine { x: 0; y: 0 }
}
}