重用TextField的组件以响应车轮事件并进行信号处理

时间:2018-08-13 09:06:46

标签: qt qml

我丰富了TextField(显示浮点数),以便可以通过鼠标滚轮更改它,而仍然可以用手对其进行编辑。

我发现了带有.tds-chart-inner { min-width: 850px !important; } .tds-hor-scroll { left: 0px; width: 100% !important; overflow-x: scroll; } canvas { left: 0px; height: 300px !important; } forceActiveFocus here的怪癖(我希望我可以像Qt一样让所有事件沿小部件堆栈传递),并使用onClicked来完成更改值(请告诉我这是否不是最好的方法):

onWheel

我想在几个地方(不复制和粘贴)重复使用此组件而不是TextField,所以我尝试这样声明该组件:

TextField{
   text: cxxObject.floatAttribute.toString()
   onEditingFinished: { cxxObject.floatAttribute=parseFloat(text); }
   MouseArea{
      anchors.fill: parent
      propagateComposedEvent: true
      onClicked: { parent.forceActiveFocus(); }
      onWheel: { parent.text=parseFloat(parent.text)-.5*wheel.angleDelta.y/120;
         parent.editingFinished();
      }
   }

并重复使用:

Component{
    id: wheeledFloatTextField
    property real initValue: 0.
    property real dWheel: 0.5
    signal editingFinished(real value);
    TextField{
        text: parent.initValue.toString();
        // re-emit signal to the component
        // so that user-defined slot can be defined when re-used
        onEditingFinished: parent.editingFinished(parseFloat(text));
        // validator: ...
        MouseArea{
            anchors.fill: parent
            propagateComposedEvents: true
            onClicked: { parent.forceActiveFocus();  }
            onWheel: {
                parent.text=parseFloat(parent.text)-parent.parent.dWheel*wheel.angleDelta.y/120;
                parent.editingFinished();
            }
        }
    }
}

但是我得到了(在使用Loader{ sourceComponent: wheeledFloatTextField initValue: cxxObject.floatAttribute; onEditingFinished: { cxxObject.floatAttribute=value; } } 的那一行):

Component

怎么了?我收集了一些帖子(例如How do you assign a QML Item to a component property in QML and then use that object inside the component?https://developer.blackberry.com/native/documentation/dev/custom_components/index.html),我可能需要将Component objects cannot declare new properties. 的内部包裹起来(就好像它是单独的{{1} }文件,但未定义范围,例如Component.qml,但我不确定该怎么做。有提示吗?

我想先保持内联定义,然后再移至单独的文件。

1 个答案:

答案 0 :(得分:1)

如果在单独的文件中声明了组件,则可以(应该)省略顶级Component。为了最大程度地重用组件,建议在单独的文件中声明它们。
Component不能声明任何属性。它基本上是在原型状态下停止对象的创建。如果要配置对象以便以后创建,例如延迟初始化(委托),这将很有用。
如果您拥有Component类型的属性,并且使用了myProp: SomeType {...}语法,它将自动从中创建一个组件。

我认为最好的解决方案是将TextField放在单独的文件中,并将属性添加到根节点,以便可以自定义。

File1(例如“ CustomTextField.qml”)

TextField{
    property real initValue: 0.
    property real dWheel: 0.5
    signal editingFinished(real value);
    text: initValue.toString();
    // re-emit signal to the component
    // so that user-defined slot can be defined when re-used
    onEditingFinished: editingFinished(parseFloat(text));
    // validator: ...
    MouseArea{
        anchors.fill: parent
        propagateComposedEvents: true
        onClicked: { parent.forceActiveFocus();  }
        onWheel: {
            parent.text=parseFloat(parent.text)-parent.parent.dWheel*wheel.angleDelta.y/120;
            parent.editingFinished();
        }
    }
}

然后您可以以所有已知的方式(例如在Loader中)重用Component:

Loader {
    sourceComponent: CustomTextField { // Property type is component, so it automatically creates a Component instead of the full-blown object, until it is loaded.
        initValue: 12
        dWheel: 42
    }
    ...
}

或没有加载程序

CustomTextField {
    ...
}

您当然可以使其内联,但是即使如此,您也必须将属性添加到Component内的根元素 中。

Component {
    id: componentId // only thing you can set besides one Object in a Component
    TextField{
        id: componentRoot // You can't reference this id from outside the Component!!!
        property real initValue: 0.
        property real dWheel: 0.5
        signal editingFinished(real value);
        text: initValue.toString();
        // re-emit signal to the component
        // so that user-defined slot can be defined when re-used
        onEditingFinished: editingFinished(parseFloat(text));
        // validator: ...
        MouseArea{
            anchors.fill: parent
            propagateComposedEvents: true
            onClicked: { parent.forceActiveFocus();  }
            onWheel: {
                parent.text=parseFloat(parent.text)-parent.parent.dWheel*wheel.angleDelta.y/120;
                parent.editingFinished();
            }
        }
    }
}

这有一个缺点,那就是您将始终需要一个单独的对象来实例化该组件,例如Loader,这会增加开销并使对象之间的文件通信复杂化,因为要解决该问题,您需要要使用:loaderId.item.property,这在查找中可能会很昂贵,您需要确保定义了item