Qt 重新使用TextField组件响应车轮事件,并进行信号处理

Qt 重新使用TextField组件响应车轮事件,并进行信号处理,qt,qml,Qt,Qml,我丰富了一个文本字段(显示一个浮动),这样它就可以通过鼠标滚轮进行更改,同时仍然可以手动编辑 我发现了forceActiveFocus和onClicked的怪癖(我希望我能像Qt一样让所有事件沿着小部件堆栈传递),并使用onWheel更改值(如果这不是最好的方法,请告诉我): 我想在多个地方重复使用此组件而不是TextField(无需复制和粘贴),因此我尝试如下方式声明该组件: Component{ id: wheeledFloatTextField property real

我丰富了一个文本字段(显示一个浮动),这样它就可以通过鼠标滚轮进行更改,同时仍然可以手动编辑

我发现了
forceActiveFocus
onClicked
的怪癖(我希望我能像Qt一样让所有事件沿着小部件堆栈传递),并使用
onWheel
更改值(如果这不是最好的方法,请告诉我):

我想在多个地方重复使用此组件而不是TextField(无需复制和粘贴),因此我尝试如下方式声明该组件:

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; }
}
然而,我得到(在使用
组件的行中):

怎么了?我收集了一些帖子(如和),我可能需要将
组件
的内部(好像它是一个单独的
.qml
文件,并且没有定义范围)封装在
容器
中,但我不确定该怎么做。有什么提示吗


我希望先将定义内联,然后移动到单独的文件。

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

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

文件1(例如“CustomTextField.qml”)

然后,您可以以所有已知的方式重用组件,如在加载程序中:

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 {
    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();
            }
        }
    }
}
这样做的缺点是,您总是需要一个单独的对象来实例化组件,比如
加载程序
,这会增加开销并使对象之间的文件通信复杂化,因为要解决它,您需要使用:
loaderId.item.property
,这在查找时可能会很昂贵,您需要确保
项目
已定义为e.t.c

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 {
    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();
            }
        }
    }
}