DiagramDesigner/PropertyEditor/resources/Qml/ValueEditor/SizeFBox.qml

373 lines
11 KiB
QML
Raw Normal View History

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)
}
}
}