微调框数字下的 QtQuick 按钮
QtQuick buttons under spinbox numbers
我想要一个旋转框,每个数字下面都有小按钮。根据选中的按钮,旋转框的步长将相应调整。例如,如果选择小数点左边的第一个按钮,则步长为 1,如果选择小数点右边的第一个按钮,则步长为 0.1。
我已经弄清楚如何获得我想要的所有行为,并且我已经将旋转框与适当的按钮组合在一起。
下一步是调整按钮的大小和位置,使它们直接排列在相应的数字位置下方。在非常低的级别上,这将涉及获取字体详细信息、确定每个数字的大小和位置,然后相应地调整按钮的大小和位置。这是我可以在 qml 中实现的吗?
这是上面按钮的 qml:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
Item {
id: root
property int decimalsLeft: 2
property int decimalsRight: 3
property alias maximumValue: spinBox.maximumValue
property alias minimumValue: spinBox.minimumValue
property alias value: spinBox.value
width: layout.width
height: layout.height
ColumnLayout {
id: layout
SpinBox {
id: spinBox
Layout.fillWidth: true
width: parent.width
decimals: root.decimalsRight
horizontalAlignment: Qt.AlignRight
maximumValue: 1e3
minimumValue: -1e3
}
// Make row of buttons under number to select
// step size
ExclusiveGroup {id: decimalSelector}
RowLayout{
Repeater {
id: rdButtons
RadioButton {
exclusiveGroup: decimalSelector
onCheckedChanged: {
if(!checked) {
return
}
var relIndex = decimalsLeft-index-1
if(relIndex == -1) {// decimal location so don't do anything
return
}
if(relIndex < 0) {
relIndex += 1
}
spinBox.stepSize = Math.pow(10, relIndex)
}
}
onModelChanged: {
for(var i=0; i<rdButtons.count; i++) {
rdButtons.itemAt(i).enabled = true
}
// disable selector associated with the decimal point
if(rdButtons.count > decimalsLeft) {
rdButtons.itemAt(decimalsLeft).enabled = false
}
// now find which selector matches our current step size
var log = Math.round(Math.log(spinBox.stepSize) / Math.LN10)
var idx = -1
if(log >= 0) {
idx = decimalsLeft-log-1
}
else {
idx = decimalsLeft-log
}
// an finally apply the selection
if(rdButtons.count == 0) {
return
}
else if(idx < 0) {
rdButtons.itemAt(0).checked = true
}
else if(idx >= rdButtons.count) {
if(idx == decimalsLeft+1) {
rdButtons.itemAt(rdButtons.count-2).checked = true
}
else {
rdButtons.itemAt(rdButtons.count-1).checked = true
}
}
else {
rdButtons.itemAt(idx).checked = true
}
}
model: decimalsLeft + decimalsRight + 1
Component.onCompleted: {
if(decimalsLeft < rdButtons.count) {
rdButtons.itemAt(decimalsLeft).enabled = false
}
if(decimalsLeft > 0) {
rdButtons.itemAt(decimalsLeft-1).checked = true
}
}
}
}
}
}
您可以使用 FontMetrics. If you know that the characters in the font you're using are all around the same size, you can use averageCharacterWidth, otherwise you can use the boundingRect property of TextMetrics 在 QML 中获取字符串的每个单独字符的字体信息。在这些类型中,properties/functions 有一些替代方案;查看文档。
您可能需要增加 SpinBox
中使用的 font 的 pixelSize
和 letterSpacing
,因为它们在默认情况下非常靠近,这不会给单选按钮留下太多空间。
访问样式委托实例的大小(incrementControl/decrementControl) will be necessary to find the position at which the text is right aligned. This means you'll need to create your own SpinBoxStyle 以便您可以为这些实例提供 ID,以便在其他地方访问它们。
但是,控件无法解决所有问题,而这个问题非常具体。此时,创建自己的 DecimalSpinBox
组件可能会更容易。然后您可以完全控制字符和单选按钮的位置。一旦您创建了自己的样式(上面提到的以前的方法),您无论如何都会失去原生样式。
我想要一个旋转框,每个数字下面都有小按钮。根据选中的按钮,旋转框的步长将相应调整。例如,如果选择小数点左边的第一个按钮,则步长为 1,如果选择小数点右边的第一个按钮,则步长为 0.1。
我已经弄清楚如何获得我想要的所有行为,并且我已经将旋转框与适当的按钮组合在一起。
下一步是调整按钮的大小和位置,使它们直接排列在相应的数字位置下方。在非常低的级别上,这将涉及获取字体详细信息、确定每个数字的大小和位置,然后相应地调整按钮的大小和位置。这是我可以在 qml 中实现的吗?
这是上面按钮的 qml:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
Item {
id: root
property int decimalsLeft: 2
property int decimalsRight: 3
property alias maximumValue: spinBox.maximumValue
property alias minimumValue: spinBox.minimumValue
property alias value: spinBox.value
width: layout.width
height: layout.height
ColumnLayout {
id: layout
SpinBox {
id: spinBox
Layout.fillWidth: true
width: parent.width
decimals: root.decimalsRight
horizontalAlignment: Qt.AlignRight
maximumValue: 1e3
minimumValue: -1e3
}
// Make row of buttons under number to select
// step size
ExclusiveGroup {id: decimalSelector}
RowLayout{
Repeater {
id: rdButtons
RadioButton {
exclusiveGroup: decimalSelector
onCheckedChanged: {
if(!checked) {
return
}
var relIndex = decimalsLeft-index-1
if(relIndex == -1) {// decimal location so don't do anything
return
}
if(relIndex < 0) {
relIndex += 1
}
spinBox.stepSize = Math.pow(10, relIndex)
}
}
onModelChanged: {
for(var i=0; i<rdButtons.count; i++) {
rdButtons.itemAt(i).enabled = true
}
// disable selector associated with the decimal point
if(rdButtons.count > decimalsLeft) {
rdButtons.itemAt(decimalsLeft).enabled = false
}
// now find which selector matches our current step size
var log = Math.round(Math.log(spinBox.stepSize) / Math.LN10)
var idx = -1
if(log >= 0) {
idx = decimalsLeft-log-1
}
else {
idx = decimalsLeft-log
}
// an finally apply the selection
if(rdButtons.count == 0) {
return
}
else if(idx < 0) {
rdButtons.itemAt(0).checked = true
}
else if(idx >= rdButtons.count) {
if(idx == decimalsLeft+1) {
rdButtons.itemAt(rdButtons.count-2).checked = true
}
else {
rdButtons.itemAt(rdButtons.count-1).checked = true
}
}
else {
rdButtons.itemAt(idx).checked = true
}
}
model: decimalsLeft + decimalsRight + 1
Component.onCompleted: {
if(decimalsLeft < rdButtons.count) {
rdButtons.itemAt(decimalsLeft).enabled = false
}
if(decimalsLeft > 0) {
rdButtons.itemAt(decimalsLeft-1).checked = true
}
}
}
}
}
}
您可以使用 FontMetrics. If you know that the characters in the font you're using are all around the same size, you can use averageCharacterWidth, otherwise you can use the boundingRect property of TextMetrics 在 QML 中获取字符串的每个单独字符的字体信息。在这些类型中,properties/functions 有一些替代方案;查看文档。
您可能需要增加 SpinBox
中使用的 font 的 pixelSize
和 letterSpacing
,因为它们在默认情况下非常靠近,这不会给单选按钮留下太多空间。
访问样式委托实例的大小(incrementControl/decrementControl) will be necessary to find the position at which the text is right aligned. This means you'll need to create your own SpinBoxStyle 以便您可以为这些实例提供 ID,以便在其他地方访问它们。
但是,控件无法解决所有问题,而这个问题非常具体。此时,创建自己的 DecimalSpinBox
组件可能会更容易。然后您可以完全控制字符和单选按钮的位置。一旦您创建了自己的样式(上面提到的以前的方法),您无论如何都会失去原生样式。