add baseType QPoint/QRect/QSize/bool to lib propertyEditor
This commit is contained in:
parent
5592c20747
commit
3843720e06
|
|
@ -23,5 +23,9 @@
|
|||
<file>resources/Qml/ValueEditor/FileSelector.qml</file>
|
||||
<file>resources/Qml/ValueEditor/LineTextBox.qml</file>
|
||||
<file>resources/Qml/ValueEditor/MultiLineTextBox.qml</file>
|
||||
<file>resources/Qml/ValueEditor/PointFBox.qml</file>
|
||||
<file>resources/Qml/ValueEditor/RectFBox.qml</file>
|
||||
<file>resources/Qml/ValueEditor/SizeFBox.qml</file>
|
||||
<file>resources/Qml/ValueEditor/BoolBox.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Shapes
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
// 保持与框架一致的接口
|
||||
property var value: false
|
||||
property int decimals: 0
|
||||
property string text: "Enabled"
|
||||
property color textColor: "black"
|
||||
property color checkedColor: "#2196F3"
|
||||
property color uncheckedColor: "#cccccc"
|
||||
property color checkedBoxColor: "white"
|
||||
property color uncheckedBoxColor: "white"
|
||||
property int boxSize: 16
|
||||
property int spacing: 8
|
||||
property int textSize: 12
|
||||
property alias font: label.font
|
||||
|
||||
// 与框架一致的信号
|
||||
signal asValueChanged(value: var)
|
||||
signal boolValueChanged(bool checked) // 辅助信号,避免与内置信号冲突
|
||||
|
||||
implicitHeight: Math.max(boxSize, label.implicitHeight)
|
||||
implicitWidth: boxSize + spacing + label.implicitWidth
|
||||
|
||||
function toggle() {
|
||||
var newValue = !getBoolValue()
|
||||
setValue(newValue)
|
||||
}
|
||||
|
||||
function setValue(newValue) {
|
||||
var boolValue = getBoolValue()
|
||||
var newBoolValue = toBool(newValue)
|
||||
|
||||
if (boolValue !== newBoolValue) {
|
||||
value = newBoolValue
|
||||
boolValueChanged(newBoolValue)
|
||||
asValueChanged(newBoolValue)
|
||||
}
|
||||
}
|
||||
|
||||
function getBoolValue() {
|
||||
return toBool(value)
|
||||
}
|
||||
|
||||
function toBool(value) {
|
||||
if (typeof value === 'boolean') {
|
||||
return value
|
||||
} else if (typeof value === 'number') {
|
||||
return value !== 0
|
||||
} else if (typeof value === 'string') {
|
||||
var str = value.toString().toLowerCase()
|
||||
return str === 'true' || str === '1' || str === 'on'
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 整个区域的点击事件
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: function(mouse) {
|
||||
control.toggle()
|
||||
mouse.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: control.spacing
|
||||
|
||||
// 复选框
|
||||
Rectangle {
|
||||
id: checkBox
|
||||
width: control.boxSize
|
||||
height: control.boxSize
|
||||
radius: 3
|
||||
border.color: getBoolValue() ? control.checkedColor : control.uncheckedColor
|
||||
border.width: 1
|
||||
color: getBoolValue() ? control.checkedColor : control.uncheckedBoxColor
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
// 勾选标记
|
||||
Shape {
|
||||
anchors.centerIn: parent
|
||||
width: 10
|
||||
height: 8
|
||||
visible: getBoolValue()
|
||||
|
||||
ShapePath {
|
||||
strokeColor: "transparent"
|
||||
fillColor: control.checkedBoxColor
|
||||
strokeWidth: 0
|
||||
|
||||
PathMove { x: 0; y: 4 }
|
||||
PathLine { x: 4; y: 8 }
|
||||
PathLine { x: 10; y: 0 }
|
||||
PathLine { x: 9; y: 0 }
|
||||
PathLine { x: 4; y: 7 }
|
||||
PathLine { x: 1; y: 4 }
|
||||
}
|
||||
}
|
||||
|
||||
// 悬停效果
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: "transparent"
|
||||
border.color: "#888888"
|
||||
border.width: boxMouseArea.containsMouse ? 1 : 0
|
||||
opacity: boxMouseArea.containsMouse ? 0.3 : 0
|
||||
}
|
||||
|
||||
// 复选框自身的点击事件
|
||||
MouseArea {
|
||||
id: boxMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: function(mouse) {
|
||||
control.toggle()
|
||||
mouse.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签文本
|
||||
Label {
|
||||
id: label
|
||||
text: control.text
|
||||
color: control.textColor
|
||||
font.pixelSize: control.textSize
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
|
||||
// 鼠标悬停在文本上时的点击事件
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: function(mouse) {
|
||||
control.toggle()
|
||||
mouse.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 键盘支持
|
||||
Keys.onPressed: function(event) {
|
||||
if (event.key === Qt.Key_Space || event.key === Qt.Key_Return) {
|
||||
control.toggle()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
// 聚焦支持
|
||||
activeFocusOnTab: true
|
||||
|
||||
// 聚焦时的边框
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: control.activeFocus ? "#2196F3" : "transparent"
|
||||
border.width: 2
|
||||
radius: 2
|
||||
visible: control.activeFocus
|
||||
}
|
||||
|
||||
// 当value从外部改变时,更新显示
|
||||
onValueChanged: {
|
||||
var boolValue = getBoolValue()
|
||||
if (checkBox.border.color !== (boolValue ? control.checkedColor : control.uncheckedColor)) {
|
||||
checkBox.border.color = boolValue ? control.checkedColor : control.uncheckedColor
|
||||
checkBox.color = boolValue ? control.checkedColor : control.uncheckedBoxColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property var value: Qt.point(0, 0)
|
||||
property int decimals: 2
|
||||
implicitHeight: 25
|
||||
implicitWidth: 120 // 设置默认宽度
|
||||
|
||||
signal asValueChanged(value: var)
|
||||
|
||||
function setValue(newValue: var) {
|
||||
if (!control.value ||
|
||||
Math.abs(control.value.x - newValue.x) > 0.000001 ||
|
||||
Math.abs(control.value.y - newValue.y) > 0.000001) {
|
||||
value = newValue
|
||||
asValueChanged(value)
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 4 // 减小间距
|
||||
|
||||
Label {
|
||||
text: "X:"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: xBox
|
||||
Layout.preferredWidth: 60 // 减小宽度
|
||||
Layout.preferredHeight: 22
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: control.value ? control.value.x.toFixed(control.decimals) : "0.00"
|
||||
font.pixelSize: 10
|
||||
leftPadding: 4
|
||||
rightPadding: 4
|
||||
selectByMouse: true
|
||||
|
||||
// 双击全选的处理
|
||||
MouseArea {
|
||||
id: xMouseArea
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
parent.selectAll()
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = true
|
||||
}
|
||||
|
||||
onClicked: function(mouse) {
|
||||
// 单击时设置焦点但不全选
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// 如果不是双击触发的焦点变化,就全选文本
|
||||
if (!xMouseArea.containsPress) {
|
||||
selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validator: DoubleValidator {
|
||||
bottom: -999999
|
||||
top: 999999
|
||||
decimals: 2
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: xBox.enabled ? "white" : "#f0f0f0"
|
||||
border.color: xBox.activeFocus ? "#2196F3" : "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
var xValue = parseFloat(text)
|
||||
if (!isNaN(xValue) && control.value) {
|
||||
control.setValue(Qt.point(xValue, control.value.y))
|
||||
} else {
|
||||
xBox.text = control.value ? control.value.x.toFixed(control.decimals) : "0.00"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Y:"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: yBox
|
||||
Layout.preferredWidth: 60
|
||||
Layout.preferredHeight: 22
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: control.value ? control.value.y.toFixed(control.decimals) : "0.00"
|
||||
font.pixelSize: 10
|
||||
leftPadding: 4
|
||||
rightPadding: 4
|
||||
selectByMouse: true
|
||||
|
||||
// 双击全选的处理
|
||||
MouseArea {
|
||||
id: yMouseArea
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
parent.selectAll()
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = true
|
||||
}
|
||||
|
||||
onClicked: function(mouse) {
|
||||
// 单击时设置焦点但不全选
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// 如果不是双击触发的焦点变化,就全选文本
|
||||
if (!yMouseArea.containsPress) {
|
||||
selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validator: DoubleValidator {
|
||||
bottom: -999999
|
||||
top: 999999
|
||||
decimals: 2
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: yBox.enabled ? "white" : "#f0f0f0"
|
||||
border.color: yBox.activeFocus ? "#2196F3" : "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
var yValue = parseFloat(text)
|
||||
if (!isNaN(yValue) && control.value) {
|
||||
control.setValue(Qt.point(control.value.x, yValue))
|
||||
} else {
|
||||
yBox.text = control.value ? control.value.y.toFixed(control.decimals) : "0.00"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
// 当value从外部改变时,更新输入框显示
|
||||
onValueChanged: {
|
||||
if (value) {
|
||||
if (!xBox.activeFocus) {
|
||||
xBox.text = value.x.toFixed(decimals)
|
||||
}
|
||||
if (!yBox.activeFocus) {
|
||||
yBox.text = value.y.toFixed(decimals)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
property var value: Qt.rect(0, 0, 0, 0)
|
||||
property int decimals: 1
|
||||
implicitHeight: 25
|
||||
implicitWidth: 240
|
||||
|
||||
signal asValueChanged(value: var)
|
||||
|
||||
function setValue(newValue) {
|
||||
if (!control.value ||
|
||||
Math.abs(control.value.x - newValue.x) > 0.000001 ||
|
||||
Math.abs(control.value.y - newValue.y) > 0.000001 ||
|
||||
Math.abs(control.value.width - newValue.width) > 0.000001 ||
|
||||
Math.abs(control.value.height - newValue.height) > 0.000001) {
|
||||
value = newValue
|
||||
asValueChanged(value)
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: [
|
||||
{ label: "X", prop: "x", validator: [-999999, 999999] },
|
||||
{ label: "Y", prop: "y", validator: [-999999, 999999] },
|
||||
{ label: "W", prop: "width", validator: [0, 999999] },
|
||||
{ label: "H", prop: "height", validator: [0, 999999] }
|
||||
]
|
||||
|
||||
RowLayout {
|
||||
id: inputRow
|
||||
spacing: 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
property string propertyName: modelData.prop
|
||||
property var textField: inputField
|
||||
|
||||
Label {
|
||||
text: modelData.label + ":"
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: inputField
|
||||
Layout.preferredWidth: 60
|
||||
Layout.preferredHeight: 22
|
||||
text: control.value ? control.value[modelData.prop].toFixed(control.decimals) : "0.0"
|
||||
font.pixelSize: 9
|
||||
padding: 2
|
||||
selectByMouse: true
|
||||
|
||||
// 双击全选的处理
|
||||
MouseArea {
|
||||
id: fieldMouseArea
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
parent.selectAll()
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = true
|
||||
}
|
||||
|
||||
onClicked: function(mouse) {
|
||||
// 单击时设置焦点但不全选
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// 如果不是双击触发的焦点变化,就全选文本
|
||||
if (!fieldMouseArea.containsPress) {
|
||||
selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validator: DoubleValidator {
|
||||
bottom: modelData.validator[0]
|
||||
top: modelData.validator[1]
|
||||
decimals: 2
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
border.color: parent.activeFocus ? "#0066cc" : "#999999"
|
||||
border.width: 1
|
||||
radius: 1
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
var val = parseFloat(text)
|
||||
if (!isNaN(val) && control.value) {
|
||||
var newRect = Qt.rect(
|
||||
modelData.prop === "x" ? val : control.value.x,
|
||||
modelData.prop === "y" ? val : control.value.y,
|
||||
modelData.prop === "width" ? val : control.value.width,
|
||||
modelData.prop === "height" ? val : control.value.height
|
||||
)
|
||||
control.setValue(newRect)
|
||||
} else {
|
||||
text = control.value ? control.value[modelData.prop].toFixed(control.decimals) : "0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
if (!value) return
|
||||
|
||||
// 通过 Repeater 的 itemAt 方法安全访问
|
||||
var props = ["x", "y", "width", "height"]
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var item = repeater.itemAt(i)
|
||||
if (item && item.textField && !item.textField.activeFocus) {
|
||||
item.textField.text = value[props[i]].toFixed(decimals)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: control
|
||||
|
||||
// 属性定义
|
||||
property var value: Qt.size(0, 0) // QSizeF
|
||||
property int decimals: 1 // 默认小数位为1
|
||||
property int precision: 2 // 精度,允许的小数位数
|
||||
|
||||
// 尺寸相关属性
|
||||
property real minWidth: 0
|
||||
property real maxWidth: 999999
|
||||
property real minHeight: 0
|
||||
property real maxHeight: 999999
|
||||
|
||||
// 步进增量
|
||||
property real widthStep: 1.0
|
||||
property real heightStep: 1.0
|
||||
|
||||
// 是否显示步进按钮
|
||||
property bool showSpinButtons: true
|
||||
|
||||
implicitHeight: 25
|
||||
implicitWidth: showSpinButtons ? 140 : 120
|
||||
|
||||
// 信号 - 重命名避免与内置信号冲突
|
||||
signal asValueChanged(value: var)
|
||||
signal sizeWidthChanged(width: real) // 改为 sizeWidthChanged
|
||||
signal sizeHeightChanged(height: real) // 改为 sizeHeightChanged
|
||||
|
||||
// 获取宽高
|
||||
function getWidth() {
|
||||
return value ? value.width : 0
|
||||
}
|
||||
|
||||
function getHeight() {
|
||||
return value ? value.height : 0
|
||||
}
|
||||
|
||||
// 设置值
|
||||
function setValue(newValue: var) {
|
||||
if (!control.value ||
|
||||
Math.abs(control.value.width - newValue.width) > 0.000001 ||
|
||||
Math.abs(control.value.height - newValue.height) > 0.000001) {
|
||||
|
||||
// 应用边界限制
|
||||
var limitedWidth = Math.max(minWidth, Math.min(maxWidth, newValue.width))
|
||||
var limitedHeight = Math.max(minHeight, Math.min(maxHeight, newValue.height))
|
||||
|
||||
// 保留精度
|
||||
limitedWidth = parseFloat(limitedWidth.toFixed(precision))
|
||||
limitedHeight = parseFloat(limitedHeight.toFixed(precision))
|
||||
|
||||
value = Qt.size(limitedWidth, limitedHeight)
|
||||
asValueChanged(value)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置宽度
|
||||
function setWidth(width: real) {
|
||||
if (control.value && Math.abs(control.value.width - width) > 0.000001) {
|
||||
var limitedWidth = Math.max(minWidth, Math.min(maxWidth, width))
|
||||
limitedWidth = parseFloat(limitedWidth.toFixed(precision))
|
||||
control.setValue(Qt.size(limitedWidth, control.value.height))
|
||||
}
|
||||
}
|
||||
|
||||
// 设置高度
|
||||
function setHeight(height: real) {
|
||||
if (control.value && Math.abs(control.value.height - height) > 0.000001) {
|
||||
var limitedHeight = Math.max(minHeight, Math.min(maxHeight, height))
|
||||
limitedHeight = parseFloat(limitedHeight.toFixed(precision))
|
||||
control.setValue(Qt.size(control.value.width, limitedHeight))
|
||||
}
|
||||
}
|
||||
|
||||
// 步进增加/减少
|
||||
function stepWidth(positive: bool) {
|
||||
if (!control.value) return
|
||||
var step = positive ? widthStep : -widthStep
|
||||
setWidth(getWidth() + step)
|
||||
}
|
||||
|
||||
function stepHeight(positive: bool) {
|
||||
if (!control.value) return
|
||||
var step = positive ? heightStep : -heightStep
|
||||
setHeight(getHeight() + step)
|
||||
}
|
||||
|
||||
// UI布局
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 4
|
||||
|
||||
// 宽度部分
|
||||
Label {
|
||||
text: "W:"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: widthBox
|
||||
Layout.preferredWidth: 60
|
||||
Layout.preferredHeight: 22
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
selectByMouse: true // 允许鼠标选择文本
|
||||
|
||||
text: control.value ? control.value.width.toFixed(control.decimals) : "0.0"
|
||||
font.pixelSize: 10
|
||||
leftPadding: 4
|
||||
rightPadding: 4
|
||||
|
||||
// 双击全选的处理
|
||||
MouseArea {
|
||||
id: widthMouseArea
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
parent.selectAll()
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = true
|
||||
}
|
||||
|
||||
onClicked: function(mouse) {
|
||||
// 单击时设置焦点但不全选
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// 如果不是双击触发的焦点变化,就全选文本
|
||||
if (!widthMouseArea.containsPress) {
|
||||
selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证器
|
||||
validator: DoubleValidator {
|
||||
bottom: control.minWidth
|
||||
top: control.maxWidth
|
||||
decimals: control.precision
|
||||
notation: DoubleValidator.StandardNotation
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: widthBox.enabled ? "white" : "#f0f0f0"
|
||||
border.color: widthBox.activeFocus ? "#2196F3" : "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
var num = parseFloat(text)
|
||||
if (!isNaN(num) && control.value) {
|
||||
control.setWidth(num)
|
||||
} else {
|
||||
// 恢复原值
|
||||
widthBox.text = control.value ?
|
||||
control.value.width.toFixed(control.decimals) :
|
||||
"0.0"
|
||||
}
|
||||
}
|
||||
|
||||
// 键盘上下键调整
|
||||
Keys.onUpPressed: function(event) {
|
||||
control.stepWidth(true)
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
Keys.onDownPressed: function(event) {
|
||||
control.stepWidth(false)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
// 宽度步进按钮
|
||||
Row {
|
||||
visible: control.showSpinButtons
|
||||
spacing: 0
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Button {
|
||||
width: 12
|
||||
height: 11
|
||||
text: "▲"
|
||||
font.pixelSize: 6
|
||||
padding: 0
|
||||
onClicked: control.stepWidth(true)
|
||||
|
||||
background: Rectangle {
|
||||
color: parent.hovered ? "#e0e0e0" : "transparent"
|
||||
border.color: "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 12
|
||||
height: 11
|
||||
text: "▼"
|
||||
font.pixelSize: 6
|
||||
padding: 0
|
||||
onClicked: control.stepWidth(false)
|
||||
|
||||
background: Rectangle {
|
||||
color: parent.hovered ? "#e0e0e0" : "transparent"
|
||||
border.color: "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 高度部分
|
||||
Label {
|
||||
text: "H:"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: heightBox
|
||||
Layout.preferredWidth: 60
|
||||
Layout.preferredHeight: 22
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
selectByMouse: true // 允许鼠标选择文本
|
||||
|
||||
text: control.value ? control.value.height.toFixed(control.decimals) : "0.0"
|
||||
font.pixelSize: 10
|
||||
leftPadding: 4
|
||||
rightPadding: 4
|
||||
|
||||
// 双击全选的处理
|
||||
MouseArea {
|
||||
id: heightMouseArea
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.LeftButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
onDoubleClicked: function(mouse) {
|
||||
parent.selectAll()
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = true
|
||||
}
|
||||
|
||||
onClicked: function(mouse) {
|
||||
// 单击时设置焦点但不全选
|
||||
parent.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// 如果不是双击触发的焦点变化,就全选文本
|
||||
if (!heightMouseArea.containsPress) {
|
||||
selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证器
|
||||
validator: DoubleValidator {
|
||||
bottom: control.minHeight
|
||||
top: control.maxHeight
|
||||
decimals: control.precision
|
||||
notation: DoubleValidator.StandardNotation
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: heightBox.enabled ? "white" : "#f0f0f0"
|
||||
border.color: heightBox.activeFocus ? "#2196F3" : "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
var num = parseFloat(text)
|
||||
if (!isNaN(num) && control.value) {
|
||||
control.setHeight(num)
|
||||
} else {
|
||||
// 恢复原值
|
||||
heightBox.text = control.value ?
|
||||
control.value.height.toFixed(control.decimals) :
|
||||
"0.0"
|
||||
}
|
||||
}
|
||||
|
||||
// 键盘上下键调整
|
||||
Keys.onUpPressed: function(event) {
|
||||
control.stepHeight(true)
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
Keys.onDownPressed: function(event) {
|
||||
control.stepHeight(false)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
// 高度步进按钮
|
||||
Row {
|
||||
visible: control.showSpinButtons
|
||||
spacing: 0
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Button {
|
||||
width: 12
|
||||
height: 11
|
||||
text: "▲"
|
||||
font.pixelSize: 6
|
||||
padding: 0
|
||||
onClicked: control.stepHeight(true)
|
||||
|
||||
background: Rectangle {
|
||||
color: parent.hovered ? "#e0e0e0" : "transparent"
|
||||
border.color: "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 12
|
||||
height: 11
|
||||
text: "▼"
|
||||
font.pixelSize: 6
|
||||
padding: 0
|
||||
onClicked: control.stepHeight(false)
|
||||
|
||||
background: Rectangle {
|
||||
color: parent.hovered ? "#e0e0e0" : "transparent"
|
||||
border.color: "#cccccc"
|
||||
border.width: 1
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
// 当value从外部改变时,更新输入框显示
|
||||
onValueChanged: {
|
||||
if (value) {
|
||||
if (!widthBox.activeFocus) {
|
||||
widthBox.text = value.width.toFixed(decimals)
|
||||
}
|
||||
if (!heightBox.activeFocus) {
|
||||
heightBox.text = value.height.toFixed(decimals)
|
||||
}
|
||||
|
||||
// 发出单独的宽高变化信号
|
||||
sizeWidthChanged(value.width)
|
||||
sizeHeightChanged(value.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -162,6 +162,188 @@ void QQuickDetailsViewManager::RegisterBasicTypeEditor() {
|
|||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<bool>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
BoolBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QPoint>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
PointFBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QPointF>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
PointFBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QRect>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
RectFBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QRectF>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
RectFBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QSize>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
SizeFBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QSizeF>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
QQmlComponent comp(engine);
|
||||
comp.setData(R"(
|
||||
import QtQuick;
|
||||
import QtQuick.Controls;
|
||||
import "qrc:/resources/Qml/ValueEditor"
|
||||
SizeFBox{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width
|
||||
}
|
||||
)", QUrl());
|
||||
QVariantMap initialProperties;
|
||||
initialProperties["parent"] = QVariant::fromValue(parent);
|
||||
auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
|
||||
if (!comp.errors().isEmpty()) {
|
||||
qDebug() << comp.errorString();
|
||||
}
|
||||
valueEditor->setParentItem(parent);
|
||||
valueEditor->setProperty("value", handle->getVar());
|
||||
connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));
|
||||
connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
|
||||
return valueEditor;
|
||||
});
|
||||
|
||||
registerTypeEditor(QMetaType::fromType<QColor>(), [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
|
||||
QQmlEngine* engine = qmlEngine(parent);
|
||||
QQmlContext* context = qmlContext(parent);
|
||||
|
|
|
|||
Loading…
Reference in New Issue