QML中与Q_GADGET的意外绑定



我有一个小玩意:

class ZScoreParams
{
Q_GADGET
Q_PROPERTY(quint64 lag MEMBER lag);
Q_PROPERTY(qreal threshold MEMBER threshold);
Q_PROPERTY(qreal influence MEMBER influence);
public:
std::size_t lag;
double threshold;
double influence;
};
Q_DECLARE_METATYPE(ZScoreParams)

和类型为QVariant的对象的属性:

Q_PROPERTY(QVariant zscoreParams READ zscoreParams WRITE setZscoreParams NOTIFY zscoreParamsChanged)

它的getter返回QVariant{}(在QML中是null)或QVariant::fromValue(gadget_val), setter具有相同的逻辑。

我不知道如何用三个spinbox创建一个对话框来编辑我的zscoparams。什么是创造它的正确方法?

我尝试了这个ZParamsEdit.qml:

GridLayout
{
property var params
property var refreshChart: function () {}
signal zparamsChanged()
Component.onCompleted:
{
refreshChart = function ()
{
params.lag = lagEdit.value
params.threshold = thresholdEdit.value
params.influence = influenceEdit.realValue
logTable.debug("qml", JSON.stringify(params))
zparamsChanged()
}
}
Layout.margins: 5
columns: 2
flow: GridLayout.LeftToRight
Label {
text: qsTr("Lag:")
Layout.alignment: Qt.AlignRight
}
SpinBox {
id: lagEdit
value: params.lag
from: 100
to: 1000000
stepSize: 100
editable: true
Layout.alignment: Qt.AlignLeft
onValueChanged: refreshChart()
}
Label {
text: qsTr("Threshold:")
Layout.alignment: Qt.AlignRight
}
SpinBox {
id: thresholdEdit
value: params.threshold
from: 0
to: 100
stepSize: 1
editable: true
Layout.alignment: Qt.AlignLeft
onValueChanged: refreshChart()
}
Label {
text: qsTr("Influence:")
Layout.alignment: Qt.AlignRight
}
RealEdit
{
Layout.alignment: Qt.AlignLeft
id: influenceEdit
decimals: 2
realValue: params.influence
realFrom: 0
realTo: 1.0
realStepSize: 0.1
onValueChanged: refreshChart()
}
}

,然后在main.qml:

Dialog
{
id: zdlg
ZParamsEdit
{
id: zedit
}
}
IconButton {
icon.source: "images/analyze.svg"
onClicked: {
zedit.params = market.zscoreParams 
zdlg.open()
}
}

并得到了我没有预料到的效果。每当编辑框发生变化时,market.zscoreParams属性setter被调用。

如何使ZParamsEdit存储我的小工具的副本,并设置我的属性值只有一次(与小工具作为一个整体),当"OK"按钮在对话框中按下?

也试过

JSON.parse(JSON.stringify(market.zscoreParams))

但也得到了意想不到的东西。

EDIT1:

我可能找到了一个丑陋的解决方案,使用显式定义的函数创建gadget的副本:

Q_INVOKABLE QVariant cloneZScoreParams(QVariant v)
{
std::optional<ZScoreParams> val;
util::FromVariant(v, val);
return util::ToVariant(val);
}

globalSettings.cloneZScoreParams(market.zscoreParams)

在QML。

是否有更好的QT?

如果我正确理解你的问题,你只需要某种本地属性/属性来存储数据的副本,然后你需要一些函数将这些副本写回数据源。

我将如何修改你的代码:

GridLayout
{
property var params
// Copy the data into local properties
property lag: params.lag
property threshold: params.threshold
property influence: params.influence
// Only update the local properties when spinboxes change
function refreshChart()
{
lag = lagEdit.value
threshold = thresholdEdit.value
influence = influenceEdit.realValue
zparamsChanged()
}
// Call this when OK button is clicked
function save()
{
params.lag = lag
params.threshold = threshold
params.influence = influence
}
signal zparamsChanged()
...
SpinBox {
id: lagEdit
value: lag
...
onValueChanged: refreshChart()
}
SpinBox {
id: thresholdEdit
value: threshold
...
onValueChanged: refreshChart()
}
RealEdit
{
id: influenceEdit
realValue: influence
...
onValueChanged: refreshChart()
}
}

更新:

为了避免三次调用setter,可以在c++类中提供一个可调用的函数:

Q_INVOKABLE void save(quint64 l, qreal t, qreal i)
{
lag = l;
threshold = t;
influence = i;
}
现在save()函数看起来像这样:
function save()
{
params.save(lag, threshold, influence)
}

最新更新