Calqlatr
Ein Taschenrechner, der für Geräte im Quer- und Hochformat entwickelt wurde. Er nutzt benutzerdefinierte Komponenten von „ Qt Quick “ und responsive Layouts für die Benutzeroberfläche sowie JavaScript für die Anwendungslogik.

Calqlatr demonstriert verschiedene QML- und Qt Quick Funktionen, wie beispielsweise die Darstellung benutzerdefinierter Komponenten und die Verwendung responsiver Layouts. Die Anwendungslogik ist in JavaScript implementiert, die Benutzeroberfläche in QML.
Ausführen des Beispiels
Sie können das Beispiel wie folgt ausführen:
- Qt Creator
Öffnen Sie den „ Welcome “-Modus und wählen Sie das Beispiel unter „ Examples “ aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ aus dem Verzeichnis „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
Nach dem Ausführen des Beispiels sollten Sie die Anwendung wie einen normalen Taschenrechner verwenden können. Wechseln Sie auf dem Smartphone vom Hoch- in den Querformatmodus – oder passen Sie auf dem Desktop die Größe des Hauptfensters an –, um das responsive Layout zu aktivieren.
Verwendung benutzerdefinierter Komponenten
Die Calqlatr -Anwendung verwendet benutzerdefinierte Typen. Die meisten davon sind in einer eigenen, separaten .qml-Datei definiert:
Main.qmlcontent/ApplicationState.qmlcontent/BackspaceButton.qmlcontent/CalculatorButton.qmlcontent/Display.qmlcontent/NumberPad.qml
Main.qml enthält das oberste Fenster und das Stammelement. Es nutzt die anderen benutzerdefinierten Typen im Verzeichnis „ content “. Beispielsweise wird der Typ „ NumberPad “ (definiert in „ content/NumberPad.qml “) in „ Main.qml “ verwendet, um den Ziffernblock des Taschenrechners zu erstellen:
NumberPad {
id: numberPad
Layout.margins: root.margin
isPortraitMode: root.isPortraitMode
applicationState: appState
}Inline-Komponenten ermöglichen es Ihnen, mehrere Komponenten innerhalb einer „ .qml “-Datei zu deklarieren. Das Beispiel verwendet Inline-Komponenten in „ NumberPad.qml “, um zwei Komponenten zu definieren: „ DigitButton “ und „ OperatorButton “:
component DigitButton: CalculatorButton {
onClicked: {
controller.applicationState.digitPressed(text);
controller.updateDimmed();
}
}
component OperatorButton: CalculatorButton {
dimmable: true
implicitWidth: 48
textColor: controller.qtGreenColor
onClicked: {
controller.applicationState.operatorPressed(text);
controller.updateDimmed();
}
}Beide Komponenten sind vom Typ „ CalculatorButton “ (wie in „ CalculatorButton.qml “ definiert), stellen jedoch einen benutzerdefinierten Handler für das Signal „clicked“ bereit und passen einige Standardwerte der Eigenschaften an. „ DigitButton “ und „ OperatorButton “ werden dann später in „ NumberPad.qml “ instanziiert:
DigitButton {
text: "e"
dimmable: true
implicitWidth: 48
}
OperatorButton { text: "ln" }Weitere Informationen zum Definieren benutzerdefinierter QML-Komponenten finden Sie unter „Defining Object Types through QML Documents “.
Responsive Layouts
In diesem Beispiel ordnen responsive Layouts die verschiedenen UI-Komponenten sowohl für den Hoch- als auch für den Querformatmodus an. Dies wird in „ Main.qml “ deutlich, wo „ ColumnLayout “ für den Hochformatmodus und „ RowLayout “ für den Querformatmodus definiert sind:
ColumnLayout {
id: portraitMode
anchors.fill: parent
visible: root.isPortraitMode
LayoutItemProxy {
target: calcDisplay
Layout.minimumHeight: calcDisplay.minHeight
}
LayoutItemProxy {
target: numberPad
Layout.alignment: Qt.AlignHCenter
}
}
RowLayout {
id: landscapeMode
anchors.fill: parent
visible: !root.isPortraitMode
LayoutItemProxy {
target: calcDisplay
}
LayoutItemProxy {
target: numberPad
Layout.alignment: Qt.AlignVCenter
}
}Die Datei „ ColumnLayout “ stellt das Hochformat-Layout der Anwendung dar, während die Datei „ RowLayout “ das Querformat-Layout enthält. Die Eigenschaften von „ visible “ legen fest, welches Layout zu einem bestimmten Zeitpunkt verwendet wird. Das „id“-Attribut der Komponenten „ NumberPad “ und „ Display “ wird verwendet, um die Eigenschaft „ target “ der Typen „ LayoutItemProxy “ festzulegen. Dadurch können beide Layouts dieselben Inhaltselemente verwenden. Darüber hinaus können Eigenschaften innerhalb des Elements „ LayoutItemProxy “ an das „ target “ selbst weitergeleitet werden. Wenn beispielsweise das „ NumberPad “ instanziiert wird, benötigen beide Layouts ein unterschiedliches „ Layout.alignment “.
Ein responsives Layout wird auch in NumberPad.qml verwendet, wenn das Hoch- und Querformat-Layout für das NumberPad selbst definiert wird:
RowLayout {
spacing: controller.spacing
GridLayout {
id: scientificGrid
columns: 3
columnSpacing: controller.spacing
rowSpacing: controller.spacing
visible: !controller.isPortraitMode
OperatorButton {
text: "x²"
Accessible.name: "x squared"
}
OperatorButton {
text: "⅟x"
Accessible.name: "one over x"
}
OperatorButton { text: "√" }
OperatorButton {
text: "x³"
Accessible.name: "x cubed"
}
OperatorButton {
text: "sin"
Accessible.name: "sine"
}
OperatorButton {
text: "|x|"
Accessible.name: "absolute value"
}
OperatorButton { text: "log" }
OperatorButton {
text: "cos"
Accessible.name: "cosine"
}
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 {
onClicked: {
controller.applicationState.operatorPressed(this.text);
controller.updateDimmed();
}
}
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
}
}
} // RowLayoutJe nach controller.isPortraitMode enthält der Ziffernblock entweder nur die Tasten eines einfachen Taschenrechners (mainGrid) oder zusätzlich einige erweiterte Funktionen über den scientificGrid.
Animieren der Textfarben der Tasten
In der Datei „ CalculatorButton.qml “ werden auch die Textfarben der Tasten des Ziffernblocks animiert.
...
color: button.getTextColor()
Behavior on color {
ColorAnimation {
duration: 120
easing.type: Easing.OutElastic
}
}
}Die Farbwechsel werden durch die Definition eines „ Behavior “ für die Eigenschaft „ color “ animiert. Wenn eine Taste auf „ dimmed = true “ gesetzt ist, erscheint sie dunkler. Wird eine Taste gedrückt, leuchtet sie grün auf. Um die Eigenschaft „ dimmed “ aller Tasten des „ NumberPad “ dynamisch zu ändern, ruft das Signal „ buttonPressed “ die Funktion „ updateDimmed() “ von „ NumberPad “ auf.
function updateDimmed() {
for (let i = 0; i < mainGrid.children.length; i++) {
mainGrid.children[i].dimmed = applicationState.isButtonDisabled(mainGrid.children[i].text);
}
for (let j = 0; j < scientificGrid.children.length; j++) {
scientificGrid.children[j].dimmed = applicationState.isButtonDisabled(
scientificGrid.children[j].text);
}
}Durchführung von Berechnungen
Die Dateien „ calculator.js “ und „ ApplicationState.qml “ definieren die Engine des Taschenrechners. „ calculator.js “ enthält den logischen Zustand des Taschenrechners sowie Operationen zur Änderung dieses Zustands. „ ApplicationState.qml “ stellt diese API über einen QML-Typ bereit.
Schauen wir uns zunächst einmal „ calculator.js “ an:
let accumulator = 0
let pendingOperator = ""
let lastButton = ""
let digits = ""accumulator, pendingOperator, lastButton, represent – der logische Zustand des Taschenrechners.
function isOperationDisabled(op, display) {
...
}isOperationDisabled() Gibt „ true “ zurück, wenn eine Operation „ op “ basierend auf dem aktuellen Zustand der Engine und der Anzeige deaktiviert werden sollte. Andernfalls wird „ false “ zurückgegeben.
function digitPressed(op, display) {
...
}
function operatorPressed(op, display) {
...
}digitPressed() Die Funktionen „ operatorPressed() “ aktualisieren den Engine- und Anzeigestatus basierend auf den gedrückten Tasten.
ApplicationState.qml stellt die in ` calculator.js ` definierten JavaScript-Funktionen hinter einer übersichtlicheren QML-API bereit:
import QtQml
import "calculator.js" as CalcEnginecalculator.js wird unter dem Namen „ CalcEngine “ importiert.
QtObject {
required property Display display
function operatorPressed(operator) {
CalcEngine.operatorPressed(operator, display);
}
function digitPressed(digit) {
CalcEngine.digitPressed(digit, display);
}
function isButtonDisabled(op) {
return CalcEngine.isOperationDisabled(op, display);
}
}required property stellt sicher, dass eine Instanz von ` Display.qml ` im ` ApplicationState ` stets unter dem Namen ` display` verfügbar ist. ` display ` wird wiederum in den Funktionen ` operatorPressed()`, ` digitPressed() ` und ` isButtonDisabled() ` verwendet.
Quelldateien
Squish-GUI-Tests
Diese Anwendung enthält Squish-GUI-Tests, die auf Qt für Android ausgerichtet sind. Die Tests wurden mit Squish für Qt erstellt, sind in Python geschrieben und befinden sich im Testverzeichnis der Anwendung.
Wenn Sie Squish für Qt für Android verwenden, stellen Sie sicher, dass Sie den in Qt integrierten Hook nutzen und den Squish-Port mit adb weiterleiten. Falls Sie die Fehlermeldung „Cannot load library“ erhalten und „ dlopen “ fehlschlägt, deaktivieren Sie „ QT_USE_TARGET_ANDROID_BUILD_DIR “ in der CMake-Konfiguration oder entfernen Sie den Eintrag aus „ Projects->Build Settings->CMake->Current Configuration “ unter „ Qt Creator “.
Falls du keine Squish-Lizenz hast, kannst du eine kostenlose Testversion erhalten.
Siehe auch QML-Anwendungen.
© 2026 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.