Calqlatr
这是一个Qt Quick 应用程序,专为横向和纵向设备设计,使用自定义组件、响应式布局和 JavaScript 作为应用程序逻辑。
Calqlatr演示了各种 QML 和 Qt Quick功能,如显示自定义组件和使用响应式布局。应用逻辑用 JavaScript 实现,用户界面用 QML 实现。
运行示例
要从 Qt Creator,打开Welcome 模式,并从Examples 中选择示例。更多信息,请参阅Qt Creator: 教程:构建并运行。
显示自定义组件
Calqlatr应用程序中使用自定义类型。这些类型定义在各自独立的 .qml 文件中:
- BackspaceButton.qml
- 计算器按钮
- 显示.qml
- NumberPad.qml
要在Main.qml
中使用这些自定义类型,请为类型所在的content
文件夹添加导入语句:
import "content"
例如,Main.qml
中使用NumberPad
类型创建计算器的数字键盘。它嵌套在Item 类型中,该类型是Qt Quick 中所有可视化项目的基础类型:
NumberPad { id: numberPad; Layout.margins: root.margin }
自定义组件是可以在任何 QML 文件中定义的 QML 类型,它们的行为与在自己的 .qml 文件中定义的组件相同,如NumberPad.qml
。在NumberPad.qml
中定义了DigitButton
组件和OperatorButton
组件。可以在这些组件中添加新属性或修改现有属性。在这里,onReleased
处理程序将被覆盖。
component DigitButton: CalculatorButton { onReleased: { root.digitPressed(text) updateDimmed() } } component OperatorButton: CalculatorButton { onReleased: { root.operatorPressed(text) updateDimmed() } textColor: controller.qtGreenColor implicitWidth: 48 dimmable: true }
此外,NumberPad
上的不同按钮使用CalculatorButton
类型。CalculatorButton.qml
定义了按钮的基本属性,您可以在NumberPad.qml
中修改每个实例的属性。对于数字和运算符按钮,还添加了一些额外属性,如text
、width
和dimmable
属性。只要计算器引擎不接受按钮输入,就可以使用dimmable
可视化禁用(变暗)按钮。
DigitButton { text: "e" dimmable: true implicitWidth: 48 }
content
目录中还有一个名为BackSpaceButton.qml
的文件,这是CalculatorButton
的一个特例,我们希望在按钮上呈现图像而不是文本。该按钮与OperatorButton
相同,但包括icon
而不是text
:
icon.source: getIcon() icon.width: 38 icon.height: 38 icon.color: getIconColor() // include this text property as the calculator engine // differentiates buttons through text. The text is never drawn. text: "bs" property bool dimmable: true property bool dimmed: false readonly property color backgroundColor: "#222222" readonly property color borderColor: "#A9A9A9" readonly property color backspaceRedColor: "#DE2C2C" readonly property int buttonRadius: 8 function getBackgroundColor() { if (button.dimmable && button.dimmed) return backgroundColor if (button.pressed) return backspaceRedColor return backgroundColor
响应式布局
在本示例中,响应式布局为纵向和横向模式安排了不同的用户界面组件。您还可以在这两种模式之间切换。在Main.qml
中可以看到这一点,它为纵向模式定义了ColumnLayout
,为横向模式定义了RowLayout
。
ColumnLayout { id: portraitMode anchors.fill: parent visible: true LayoutItemProxy { target: display Layout.minimumHeight: display.minHeight } LayoutItemProxy { target: numberPad Layout.alignment: Qt.AlignHCenter } } RowLayout { id: landscapeMode anchors.fill: parent visible: false LayoutItemProxy { target: display } LayoutItemProxy { target: numberPad Layout.alignment: Qt.AlignVCenter } }
ColumnLayout
代表应用程序的纵向布局,而RowLayout
代表横向布局。visible
属性用于处理在特定时间使用哪种布局。NumberPad
和Display
组件的id
属性用于设置LayoutItemProxy
类型的target
属性。这样,两种布局就可以使用相同的内容项。此外,还可将LayoutItemProxy
项目内的属性转发到target
本身。例如,当NumberPad
实例化时,两种布局都需要不同的Layout.alignment
。
在isPortraitMode
属性的信号处理器中,通过设置它们的可见性,可以在两种布局之间切换:
onIsPortraitModeChanged: { if (isPortraitMode) { portraitMode.visible = true landscapeMode.visible = false } else { portraitMode.visible = false landscapeMode.visible = true } }
之所以能做到这一点,是因为 QML 为所有自声明的属性创建了信号处理程序,在本例中就是on<Property>Changed
处理程序,其中 <property> 是isPortraitMode
属性。
在NumberPad.qml
中定义NumberPad
本身的纵向和横向布局时,也使用了响应式布局。
RowLayout { spacing: controller.spacing GridLayout { id: scientificGrid columns: 3 columnSpacing: controller.spacing rowSpacing: controller.spacing visible: !isPortraitMode OperatorButton { text: "x²" } OperatorButton { text: "⅟x" } OperatorButton { text: "√" } OperatorButton { text: "x³" } OperatorButton { text: "sin" } OperatorButton { text: "|x|" } OperatorButton { text: "log" } OperatorButton { text: "cos" } DigitButton { text: "e" dimmable: true implicitWidth: 48 } OperatorButton { text: "ln" } OperatorButton { text: "tan" } DigitButton { text: "π" dimmable: true implicitWidth: 48 } } GridLayout { id: mainGrid columns: 5 columnSpacing: controller.spacing rowSpacing: controller.spacing BackspaceButton {} DigitButton { text: "7" } DigitButton { text: "8" } DigitButton { text: "9" } OperatorButton { text: "÷" implicitWidth: 38 } OperatorButton { text: "AC" textColor: controller.backspaceRedColor accentColor: controller.backspaceRedColor } DigitButton { text: "4" } DigitButton { text: "5" } DigitButton { text: "6" } OperatorButton { text: "×" implicitWidth: 38 } OperatorButton { text: "=" implicitHeight: 81 Layout.rowSpan: 2 } DigitButton { text: "1" } DigitButton { text: "2" } DigitButton { text: "3" } OperatorButton { text: "−" implicitWidth: 38 } OperatorButton { text: "±" implicitWidth: 38 } DigitButton { text: "0" } DigitButton { text: "." dimmable: true } OperatorButton { text: "+" implicitWidth: 38 } } } // RowLayout
在这种情况下,会创建两个LayoutItemProxy
项目。它们的target
属性分别设置为scientificGrid
和mainGrid
,前者是Grid
类型,包含所有科学按钮,后者是Grid
类型,包含所有标准按钮。
在CalculatorButton.qml
中,数字键盘按钮的文本颜色也是动画的。
... color: getBackgroundColor() border.color: getBorderColor() } contentItem: Text { text: button.text font.pixelSize: button.fontSize horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: getTextColor() Behavior on color { ColorAnimation { duration: 120 easing.type: Easing.OutElastic }
通过在color
属性上定义Behavior
,可以实现颜色的动画变化。当按钮设置为dimmed = true
时,按钮的颜色会变深。按下按钮时,按钮会亮起绿灯。为了动态更改NumberPad
上所有按钮的dimmed
属性,buttonPressed
信号调用NumberPad
的updateDimmed()
函数。
function updateDimmed(){ for (let i = 0; i < mainGrid.children.length; i++){ mainGrid.children[i].dimmed = root.isButtonDisabled(mainGrid.children[i].text) } for (let j = 0; j < scientificGrid.children.length; j++){ scientificGrid.children[j].dimmed = root.isButtonDisabled(scientificGrid.children[j].text) } }
执行计算
calculator.js 文件定义了计算器的引擎。它包含用于存储计算器状态的变量,以及用户按下数字和运算符按钮时调用的函数。要使用该引擎,请使用别名CalcEngine
将 calculator.js 导入Main.qml
文件:
import "content/calculator.js" as CalcEngine
默认情况下,从 QML 导入 JavaScript 文件会创建一个新实例,其中包含的任何状态都是该实例独有的。使用.pragma library
可以让脚本的所有用户共享状态。
.pragma library
当用户按下一个数字时,该数字的文本就会出现在显示屏上。按下运算符时,将执行相应的计算,并使用等式 (=) 运算符显示计算结果。全清 (AC) 运算符可重置计算器引擎。
文件列表
另请参阅 QML 应用程序。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.