185 lines
5.1 KiB
QML
185 lines
5.1 KiB
QML
|
|
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
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|