How do I skip the indices in a repeater such that I can create the following exact string: A • D • G • J • M • P • S • V • Z Is this achievable?
My new code based on suggested answers, I created a function newLetters(index) to determine which letters to print and now my output gives the following string: A •• D •• G •• J •• M •• P •• S •• V •• Z?
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property string letters: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Rectangle {
id: control
anchors.fill: parent
function newLetters(index) {
if(letters[index] === "A")
return true
if(letters[index] === "D")
return true
if(letters[index] === "G")
return true
if(letters[index] === "J")
return true
if(letters[index] === "M")
return true
if(letters[index] === "P")
return true
if(letters[index] === "S")
return true
if(letters[index] === "V")
return true
if(letters[index] === "Z")
return true
}
Repeater {
anchors.fill: parent
model: 26
Text {
text: control.newLetters(index) ? root.letters[index] : " • "
}
}
}
}
You could use a Loader as delegate.
Repeater {
id: repeater
model: 26
Loader {
sourceComponent: condition(index) ? defaultDelegate : null
}
}
here condition should be a function that returns true for the indices you want to show, and defaultDelegate is the delegate you want to show for for those indices.
Another way is to just hide the text element.
Repeater {
anchors.fill: parent
model: 26
Text {
visible: condition(index)
text: root.letters[index]
}
}
Related
My implementation is to keep track of whether I have placed the dot already •. I am trying to acheive the following: A • D • G • J • M • P • S • V • Z. The property binding for check, somehow it doesn't want to go back to 0. I also tried using a local var, but it will always be 0 or 1. How can I resolve this? I get the following error: Binding loop detected for property "text"
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: root
visible: true
anchors.fill: parent
property string letters: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
property int check: 0
readonly property real dx: 20
function midpoint(idx) {
return 20 + idx * root.dx;
}
function newLetters(index) {
if(root.letters[index] === "A"){
root.check = 0
return true
}
if(root.letters[index] === "D"){
root.check = 0
return true
}
if(root.letters[index] === "G"){
root.check = 0
return true
}
if(root.letters[index] === "J"){
root.check = 0
return true
}
if(root.letters[index] === "M"){
root.check = 0
return true
}
if(root.letters[index] === "P"){
root.check = 0
return true
}
if(root.letters[index] === "S"){
root.check = 0
return true
}
if(root.letters[index] === "V"){
root.check = 0
return true
}
if(root.letters[index] === "Z"){
root.check = 0
return true
}
else {
root.check = root.check + 1
}
}
Repeater {
model: 26
Text {
anchors.horizontalCenter: parent.left
anchors.horizontalCenterOffset: root.midpoint(index)
anchors.verticalCenter: parent.verticalCenter
text: root.newLetters(index) ? root.letters[index] : (root.check === 0 ? " • " : "")
}
}
}
}
Yes, by changing the root.check variable, the QQmlEngine will re-evaluate all bindings dependent on, including the newLetters function itself, thus leading to a binding loop.
I have been watching your recent questions (wondering what the end-goal is) and I think you should alter your newLetters function, to return the actual wanted text instead of the condition:
function newLetters(index) {
if(index < 24) //below Y, everything is regular
{
if(index % 3 == 0)
return root.letters[index]
if(index % 3 == 1)
return " ° "
}
else if(index == 24) //Y
{
return ""
}
else if(index == 25) //Z
{
return root.letters[index]
}
return ""
}
I have the score defined as below to be printed on screen
property int score: 0
Text {
id: score1
text: "Score: "+ score
anchors.bottom: grid.top
font.pointSize: 20
color: "red"
}
and this list model to access and change square colors and text values in the grid
property variant colorArray: ["cyan","red","white"]
ListModel {
id: dummyModel
ListElement {
squareColor: "white"
txt: 0
}
ListElement {
squareColor: "white"
txt: 0
}
ListElement {
squareColor: "white"
txt: 0
}
ListElement {
squareColor: "white"
txt: 0
}
}
Timer {
// to change square colors randomly
id: alfa
interval: 2000; running: true; repeat: true
onTriggered: {
for (var i=0;i<dummyModel.count;i++) {
dummyModel.setProperty(i,"squareColor",colorArray[Math.floor(Math.random()*3)])
}
}
}
Timer {
// to change score values in grid element randomly
id: beta
interval: 2000; running: true; repeat: true
onTriggered: {
for (var i=0;i<dummyModel.count;i++) {
var sc = Math.floor(Math.random()*20) // random value from 0 to 20
dummyModel.setProperty(i,"txt",sc) // score in each square
}
}
}
and this grid contains colored squares, when a square is clicked and color is cyan score should be updated by the number in the text field tttt
Grid{
id: grid
rows: 2
columns:2
spacing: 5
anchors.centerIn: parent
Repeater{
id: gridRect
model: dummyModel // from a list element model
Rectangle{
id: rect
width: 50
height: width
color: "cyan"
radius: 10
Text {
id: tttt
anchors.centerIn: parent
color: "lightBlue"
text : txt
}
MouseArea{
anchors.fill: parent
onClicked: {
if (rect.color == "cyan")
score = score + tttt.text
else if (rect.color == "red")
score = score - tttt.text
}
}
}
}
}
but score can't be updated on click instead I get this error/warning:
<Unknown File>: Can't assign to existing role 'txt' of different type [Number -> String]
why is that?
The Text component can receive any type of data: string, number, etc. and try to convert it to string, in your case when you use txt.text you are getting that converted string. So there are 2 solutions convert the string to number, or better not use the value of the Text component but the property of the model:
// ...
Rectangle{
id: rect
width: 50
height: width
color: model.squareColor
radius: 10
Text {
id: tttt
anchors.centerIn: parent
color: "lightBlue"
text : model.txt
}
MouseArea{
anchors.fill: parent
onClicked: {
if (model.squareColor === "cyan")
score = score + model.txt
else if (model.squareColor === "red")
score = score - model.txt
}
}
}
// ...
My program is starting by default in windowed mode.
My problem is if I start it and then press on maximize, then on minimize and then click on it in the taskbar, it is in windowed mode and not maximized.
To be honest I made that whole new window because I like programs that have a nice clear design. I don't know if you can change the top of a normal Window like the icon of the close button or the color of it.
main.qml:
/***********************************************************************************************************/
/*********************************************** S T A R T *************************************************/
/***********************************************************************************************************/
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls.Universal 2.0
import QtQuick.Controls.Imagine 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Dialogs.qml 1.0
import QtQuick.Extras 1.4
import QtQuick.Templates 2.5
import QtQuick.LocalStorage 2.0
ApplicationWindow {
id: mainWindow
visible: true
width: 900
height: 600
title: qsTr("Test")
color: "#2F3136"
flags: Qt.Window | Qt.FramelessWindowHint
property int _max: 0
property int _min: 0
property int _resizeRightVar: 0
property int _resizeLeftVar: 0
property int _resizeTopVar: 0
property int _resizeBottomVar: 0
property bool _resizeRight: true
property bool _resizeLeft: true
property bool _resizeTop: true
property bool _resizeBottom: true
property int _rRCursor: Qt.SizeHorCursor
property int _rLCursor: Qt.SizeHorCursor
property int _rTCursor: Qt.SizeVerCursor
property int _rBCursor: Qt.SizeVerCursor
property bool _moveWindow: true
property int previousX
property int previousY
///////////////////////////////////////////////////////////
/// TOP RECTANGLE WITH TITLE, MINIMIZE, MAXIMIZE, CLOSE ///
///////////////////////////////////////////////////////////
Rectangle {
id: rectangle
width: parent.width
height: 23
color: "#202225"
anchors.top: parent.top
//////////////////////////////////
/// TITLE IN THE TOP RECTANGLE ///
//////////////////////////////////
Text {
leftPadding: 6
topPadding: 1
opacity: 0.75
text: mainWindow.title
font.pixelSize: 14
font.family: "Dodge"
color: "white"
}
///////////////////////////////////////
/// MOUSE AREA IN THE TOP RECTANGLE ///
///////////////////////////////////////
MouseArea {
anchors.fill: parent
enabled: mainWindow._moveWindow
onPressed: {
previousX = mouseX
previousY = mouseY
}
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setX(mainWindow.x + dx)
}
onMouseYChanged: {
var dy = mouseY - previousY
mainWindow.setY(mainWindow.y + dy)
}
onDoubleClicked: {
//mainWindow.visibility = "Maximized"
mainWindow._max ++
if(mainWindow._max == 1){
mainWindow.visibility = "Maximized"
//mainWindow.showMaximized()
mainWindow._moveWindow = false
mainWindow._rRCursor = Qt.ArrowCursor
mainWindow._rLCursor = Qt.ArrowCursor
mainWindow._rTCursor = Qt.ArrowCursor
mainWindow._rBCursor = Qt.ArrowCursor
mainWindow._resizeRight = false
mainWindow._resizeLeft = false
mainWindow._resizeTop = false
mainWindow._resizeBottom = false
} else if(mainWindow._max == 2){
mainWindow.visibility = "Windowed"
//mainWindow.showNormal()
mainWindow._max = 0
mainWindow._moveWindow = true
mainWindow._rRCursor = Qt.SizeHorCursor
mainWindow._rLCursor = Qt.SizeHorCursor
mainWindow._rTCursor = Qt.SizeVerCursor
mainWindow._rBCursor = Qt.SizeVerCursor
mainWindow._resizeRight = true
mainWindow._resizeLeft = true
mainWindow._resizeTop = true
mainWindow._resizeBottom = true
}
}
}
/////////////////////////////////////////
/// CLOSE BUTTON IN THE TOP RECTANGLE ///
/////////////////////////////////////////
Rectangle {
id: close_window
width: 27
height: 22.5
anchors.top: parent.top
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
color: "#202225"
Image {
id: closeImage
source: "close_window.png"
anchors.fill: parent
opacity: 0.6
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: close_windowMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainWindow.close()
}
onEntered: {
cursorShape: Qt.PointingHandCursor
close_window.color = "#F04747"
closeImage.opacity = 1
}
onExited: {
cursorShape: Qt.ArrowCursor
close_window.color = "#202225"
closeImage.opacity = 0.6
}
}
}
////////////////////////////////////////////
/// MAXIMIZE BUTTON IN THE TOP RECTANGLE ///
////////////////////////////////////////////
Rectangle {
id: maximize_window
width: 27
height: 22.5
anchors.top: parent.top
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 29
color: "#202225"
Image {
id: maximizeImage
source: "maximize_window.png"
anchors.fill: parent
opacity: 0.6
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: maximize_windowMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainWindow._max ++
if(mainWindow._max == 1){
mainWindow.visibility = "Maximized"
//mainWindow.showMaximized()
mainWindow._moveWindow = false
mainWindow._rRCursor = Qt.ArrowCursor
mainWindow._rLCursor = Qt.ArrowCursor
mainWindow._rTCursor = Qt.ArrowCursor
mainWindow._rBCursor = Qt.ArrowCursor
mainWindow._resizeRight = false
mainWindow._resizeLeft = false
mainWindow._resizeTop = false
mainWindow._resizeBottom = false
} else if(mainWindow._max == 2){
mainWindow.visibility = "Windowed"
//mainWindow.showNormal()
mainWindow._max = 0
mainWindow._moveWindow = true
mainWindow._rRCursor = Qt.SizeHorCursor
mainWindow._rLCursor = Qt.SizeHorCursor
mainWindow._rTCursor = Qt.SizeVerCursor
mainWindow._rBCursor = Qt.SizeVerCursor
mainWindow._resizeRight = true
mainWindow._resizeLeft = true
mainWindow._resizeTop = true
mainWindow._resizeBottom = true
}
}
onEntered: {
maximize_window.color = "#2B2D30"
maximizeImage.opacity = 1
}
onExited: {
maximize_window.color = "#202225"
maximizeImage.opacity = 0.6
}
}
}
////////////////////////////////////////////
/// MINIMIZE BUTTON IN THE TOP RECTANGLE ///
////////////////////////////////////////////
Rectangle {
id: minimize_window
width: 27
height: 22.5
anchors.top: parent.top
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 57
color: "#202225"
Image {
id: minimizeImage
source: "minimize_window.png"
anchors.fill: parent
opacity: 0.6
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: minimize_windowMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainWindow._min ++
if(mainWindow._min >= 1){
mainWindow._min = 0
//mainWindow.showMinimized()
mainWindow.visibility = "Minimized"
//if(mainWindow._max == 1){
// mainWindow.showMaximized()
// mainWindow.visibility = "Maximized"
//}
}
}
onEntered: {
minimize_window.color = "#2B2D30"
minimizeImage.opacity = 1
}
onExited: {
minimize_window.color = "#202225"
minimizeImage.opacity = 0.6
}
}
}
}
///////////////////////////
/// RIGHT RESIZE WINDOW ///
///////////////////////////
MouseArea {
id: rightResize
width: 5
enabled: mainWindow._resizeRight
cursorShape: mainWindow._rRCursor
anchors {
right: parent.right
top: parent.top
bottom: parent.bottom
}
onEntered: {
if(mainWindow._resizeRight == true){
mainWindow._rRCursor = Qt.SizeHorCursor
} else if(mainWindow._resizeRight == false){
mainWindow._rRCursor = Qt.ArrowCursor
}
}
onPressed: previousX = mouseX
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setWidth(parent.width + dx)
}
}
//////////////////////////
/// LEFT RESIZE WINDOW ///
//////////////////////////
MouseArea {
id: leftResize
width: 5
enabled: mainWindow._resizeLeft
cursorShape: mainWindow._rLCursor
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
onEntered: {
if(mainWindow._resizeLeft == true){
mainWindow._rLCursor = Qt.SizeHorCursor
} else if(mainWindow._resizeLeft == false){
mainWindow._rLCursor = Qt.ArrowCursor
}
}
onPressed: previousX = mouseX
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setX(mainWindow.x + dx)
mainWindow.setWidth(mainWindow.width - dx)
}
}
/////////////////////////
/// TOP RESIZE WINDOW ///
/////////////////////////
MouseArea {
id: topResize
height: 5
enabled: mainWindow._resizeTop
cursorShape: mainWindow._rTCursor
anchors {
top: parent.top
left: parent.left
right: parent.right
}
onEntered: {
if(mainWindow._resizeTop == true){
mainWindow._rTCursor = Qt.SizeVerCursor
} else if(mainWindow._resizeTop == false){
mainWindow._rTCursor = Qt.ArrowCursor
}
}
onPressed: previousY = mouseY
onMouseYChanged: {
var dy = mouseY - previousY
mainWindow.setY(mainWindow.y + dy)
mainWindow.setHeight(mainWindow.height - dy)
}
}
////////////////////////////
/// BOTTOM RESIZE WINDOW ///
////////////////////////////
MouseArea {
id: bottomResize
height: 5
enabled: mainWindow._resizeBottom
cursorShape: mainWindow._rBCursor
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
onEntered: {
if(mainWindow._resizeBottom == true){
mainWindow._rBCursor = Qt.SizeVerCursor
} else if(mainWindow._resizeBottom == false){
mainWindow._rBCursor = Qt.ArrowCursor
}
}
onPressed: previousY = mouseY
onMouseYChanged: {
var dy = mouseY - previousY
//mainWindow.setY(mainWindow.y + dy)
mainWindow.setHeight(mainWindow.height + dy)
}
}
////////////////////////////
/// TEXT INPUT IN MIDDLE ///
////////////////////////////
Rectangle{
id: textInputBG
}
}
/***********************************************************************************************************/
/************************************************** E N D **************************************************/
/***********************************************************************************************************/
Here's a hacky way to solve this:
Add property int saved_state to your ApplicationWindow
Then add the following code:
onVisibilityChanged: {
if(saved_state === 4 && visibility === 2) {
showMaximized()
saved_state = -1
}
}
Then isnide your MouseArea minimize_sindowMouseArea add the following line:
saved_state = mainWindow.visibility //NEW LINE
mainWindow.visibility = "Minimized" //Existing line
Explanation: Save the state of your window right before you minimize, then restore it to the save_state when restored.
I don't know of any cleaner way, but that should do it :)
I have a Canvas with the image, that I load via filedialog, how can I get the pixel array of this image?
I need convert it to grayscale by converting every pixel using formula and load it back to the Canvas.
Here the code:
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
import QtQuick.Layouts 1.2
import QtQuick.Dialogs 1.0
ApplicationWindow {
id: window
visible: true
width: 1000
height: 750
Material.theme: Material.Dark
Material.background: "#2C303A"
Material.accent: "#65B486"
Material.foreground: "#efefef"
GridLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 9
columns: 4
rows: 3
rowSpacing: 10
columnSpacing: 10
Canvas {
id: canvas
height: window.height - 15
Layout.columnSpan: 4
Layout.fillWidth: true
property bool loaded: false
property var filepath: ''
onDrawChanged: requestPaint()
onFilepathChanged: {
loadImage(filepath)
}
onImageLoaded: {
loaded = true
requestPaint()
}
onPaint: {
if (loaded) {
var ctx = getContext("2d");
ctx.drawImage(filepath, 0, 0, width, height)
}
if (to_grayscale) {
var ctx = getContext("2d");
var ar = ctx.getImageData(0, 0, width, height).data
for(var i in ar){
print(i)
}
}
}
}
FileDialog {
id: fileDialog
title: "Please choose a file"
nameFilters: ["Image files (*.jpg *.png *.jpeg)"]
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)
canvas.filepath = fileDialog.fileUrls
canvas.requestPaint()
}
onRejected: {
console.log("Canceled")
}
}
Drawer {
id: drawer
visible: true
modal: false
width: 0.33 * window.width
height: window.height
GridLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 9
columns: 2
rows: 3
rowSpacing: 10
columnSpacing: 10
Button {
text: 'Load image'
onClicked: fileDialog.visible = true
}
Button {
text: 'RGB to Grayscale'
onClicked: canvas.draw = true
}
}
}
}
}
I'm trying to get ImageData, but here's empty
I read that Canvas contain PixelArray, but I don't know how to get it.
Thank you.
To access the rgba values
var ar = ctx.getImageData(0, 0, width, height);
for( var x=0; x < ar.data.length; x=x+4 )
{
// To read RGBA values
var red = ar.data[x];
var green = ar.data[x + 1];
var blue = ar.data[x + 2];
var alpha = ar.data[x + 3];
console.log(red + ", " + green + ", " + blue + ", " + alpha );
// To convert to grey scale, modify rgba according to your formula
ar.data[x] = 0.2126 *ar.data[x] + 0.7152* ar.data[x+1] + 0.0722 *ar.data[x+2];
ar.data[x+1] = 0.2126 *ar.data[x] + 0.7152* ar.data[x+1] + 0.0722 *ar.data[x+2];
ar.data[x+2] = 0.2126 *ar.data[x] + 0.7152* ar.data[x+1] + 0.0722 *ar.data[x+2];
ar.data[x+3] = 255;
}
// update the canvas with new data
ctx.drawImage(ar.data, 0, 0);
You have to requestPaint() in onClicked slot of Button
In a touchpanel application, is it possible to edit the integer value of a qml SpinBox, from QtQuickControls 2.0, in such a way that a numeric keypad appears on-screen and one can enter the exact value?
Or do you have any idea on how to embed this predefined number pad in a customized spinbox, that should pop-up when the user taps on the integer number?
The numpad can be set to be invisible and put on top of everything, then you can have a function to enable its visibility and set it's target. When you are done with typing the number, you set the target value to the numpad value, and hide it again. This way you can target different spinboxes.
As of the actual method to request the keypad, you can put a MouseArea to fill the spinbox on top of it. Or you can make the mouse area narrower, so that the plus/minus buttons of the spinbox are still clickable.
Also keep in mind that numpad you have linked is not actually functional.
Thanks for your suggestion. I came up with a first quick solution based on your idea and the number pad from the example section. I post it here, just in case it helps someone else as starting point. I am a QML beginner, so happy to get any improvements or corrections.
See attached screenshot of the numeric virtual touchpad appearing when clicking on the spinbox number
SpinBox {
id: boxCommPos
x: 50
y: 50
z: 0
width: 200
height: 50
to: 360
editable: false
contentItem: TextInput {
z: 1
text: parent.textFromValue(parent.value, parent.locale)
font: parent.font
//color: "#21be2b"
//selectionColor: "#21be2b"
//selectedTextColor: "#ffffff"
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
readOnly: !parent.editable
validator: parent.validator
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
Label {
id: commUnits
x: 125
y: 0
z: 3
text: qsTr("º")
font.pointSize: 16
anchors.right: parent.right
anchors.rightMargin: 45
}
MouseArea {
id: padCommPos
x: 40
y: 0
z: 2
width: parent.width-x-x
height: 50
onClicked: touchpad.visible=true
}
}
NumberTouchpad {
id: touchpad
x: 470
y: -20
z: 1
scale: 0.90
visible: false
Rectangle {
id: backrect
x: -parent.x/parent.scale
z: -1
width: parent.parent.width/parent.scale
height: parent.parent.height/parent.scale
color: "#eceeea"
opacity: 0.5
MouseArea {
anchors.fill: parent
}
}
}
The file NumberPad.qml
import QtQuick 2.0
Grid {
columns: 3
columnSpacing: 32
rowSpacing: 16
signal buttonPressed
Button { text: "7" }
Button { text: "8" }
Button { text: "9" }
Button { text: "4" }
Button { text: "5" }
Button { text: "6" }
Button { text: "1" }
Button { text: "2" }
Button { text: "3" }
Button { text: "0" }
Button { text: "."; dimmable: true }
//Button { text: " " }
Button { text: "±"; color: "#6da43d"; operator: true; dimmable: true }
//Button { text: "−"; color: "#6da43d"; operator: true; dimmable: true }
//Button { text: "+"; color: "#6da43d"; operator: true; dimmable: true }
//Button { text: "√"; color: "#6da43d"; operator: true; dimmable: true }
//Button { text: "÷"; color: "#6da43d"; operator: true; dimmable: true }
//Button { text: "×"; color: "#6da43d"; operator: true; dimmable: true }
Button { text: "C"; color: "#6da43d"; operator: true }
Button { text: "✔"; color: "#6da43d"; operator: true; dimmable: true }
Button { text: "X"; color: "#6da43d"; operator: true }
}
Display.qml
// Copyright (C) 2015 The Qt Company Ltd.
import QtQuick 2.0
import QtQuick.Window 2.0
Item {
id: display
property real fontSize: Math.floor(Screen.pixelDensity * 10.0)
property string fontColor: "#000000"
property bool enteringDigits: false
property int maxDigits: (width / fontSize) + 1
property string displayedOperand
property string errorString: qsTr("ERROR")
property bool isError: displayedOperand === errorString
function displayOperator(operator)
{
listView.model.append({ "operator": operator, "operand": "" })
enteringDigits = true
listView.positionViewAtEnd()
//console.log("display",operator);
}
function newLine(operator, operand)
{
displayedOperand = displayNumber(operand)
listView.model.append({ "operator": operator, "operand": displayedOperand })
enteringDigits = false
listView.positionViewAtEnd()
//console.log("newLine",operator);
}
function appendDigit(digit)
{
if (!enteringDigits)
listView.model.append({ "operator": "", "operand": "" })
var i = listView.model.count - 1;
listView.model.get(i).operand = listView.model.get(i).operand + digit;
enteringDigits = true
listView.positionViewAtEnd()
//console.log("num is ", digit);
}
function setDigit(digit)
{
var i = listView.model.count - 1;
listView.model.get(i).operand = digit;
listView.positionViewAtEnd()
//console.log("setDigit",digit);
}
function clear()
{
displayedOperand = ""
if (enteringDigits) {
var i = listView.model.count - 1
if (i >= 0)
listView.model.remove(i)
enteringDigits = false
}
//console.log("clearing");
}
// Returns a string representation of a number that fits in
// display.maxDigits characters, trying to keep as much precision
// as possible. If the number cannot be displayed, returns an
// error string.
function displayNumber(num) {
if (typeof(num) != "number")
return errorString;
var intNum = parseInt(num);
var intLen = intNum.toString().length;
// Do not count the minus sign as a digit
var maxLen = num < 0 ? maxDigits + 1 : maxDigits;
if (num.toString().length <= maxLen) {
if (isFinite(num))
return num.toString();
return errorString;
}
// Integer part of the number is too long - try
// an exponential notation
if (intNum == num || intLen > maxLen - 3) {
var expVal = num.toExponential(maxDigits - 6).toString();
if (expVal.length <= maxLen)
return expVal;
}
// Try a float presentation with fixed number of digits
var floatStr = parseFloat(num).toFixed(maxDigits - intLen - 1).toString();
if (floatStr.length <= maxLen)
return floatStr;
return errorString;
}
Item {
id: theItem
width: parent.width
height: parent.height
Rectangle {
id: rect
x: 0
color: "#eceeea"
height: parent.height
width: display.width
}
/*Image {
anchors.right: rect.left
source: "images/paper-edge-left.png"
height: parent.height
fillMode: Image.TileVertically
}
Image {
anchors.left: rect.right
source: "images/paper-edge-right.png"
height: parent.height
fillMode: Image.TileVertically
}
Image {
id: grip
source: "images/paper-grip.png"
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
}*/
ListView {
id: listView
width: display.width
height: display.height
delegate: Item {
height: display.fontSize * 1.1
width: parent.width
Text {
id: operator
font.pixelSize: display.fontSize
color: "#6da43d"
text: model.operator
}
Text {
id: operand
y:5
font.pixelSize: display.fontSize
color: display.fontColor
anchors.right: parent.right
anchors.rightMargin: 22
text: model.operand
}
}
model: ListModel { }
}
}
}
calculator.qs
// Copyright (C) 2015 The Qt Company Ltd.
var curVal = 0
var memory = 0
var lastOp = ""
var previousOperator = ""
var digits = ""
function disabled(op) {
if (op == "✔")
display.fontColor="#000000"
if (op=="X")
return false
else if (op == "✔" && (digits.toString().search(/\./) != -1 || digits.toString().search(/-/)!= -1 || parseInt(digits)>359)) {
display.fontColor="#ff0000"
return true
}
else if (digits == "" && !((op >= "0" && op <= "9") || op == "."))
return true
else if (op == '=' && previousOperator.length != 1)
return true
else if (op == "." && digits.toString().search(/\./) != -1) {
return true
} else if (op == "√" && digits.toString().search(/-/) != -1) {
return true
} else {
return false
}
}
function digitPressed(op)
{
if (disabled(op))
return
if (digits.toString().length >= display.maxDigits)
return
if (lastOp.toString().length == 1 && ((lastOp >= "0" && lastOp <= "9") || lastOp == ".") ) {
digits = digits + op.toString()
display.appendDigit(op.toString())
} else {
digits = op
display.appendDigit(op.toString())
}
lastOp = op
}
function operatorPressed(op)
{
if (disabled(op))
return
lastOp = op
if (op == "±") {
digits = Number(digits.valueOf() * -1)
display.setDigit(display.displayNumber(digits))
return
}
if (previousOperator == "+") {
digits = Number(digits.valueOf()) + Number(curVal.valueOf())
} else if (previousOperator == "−") {
digits = Number(curVal.valueOf()) - Number(digits.valueOf())
} else if (previousOperator == "×") {
digits = Number(curVal) * Number(digits.valueOf())
} else if (previousOperator == "÷") {
digits = Number(curVal) / Number(digits.valueOf())
}
if (op == "+" || op == "−" || op == "×" || op == "÷") {
previousOperator = op
curVal = digits.valueOf()
digits = ""
display.displayOperator(previousOperator)
return
}
if (op == "=") {
display.newLine("=", digits.valueOf())
}
curVal = 0
previousOperator = ""
if (op == "1/x") {
digits = (1 / digits.valueOf()).toString()
} else if (op == "x^2") {
digits = (digits.valueOf() * digits.valueOf()).toString()
} else if (op == "Abs") {
digits = (Math.abs(digits.valueOf())).toString()
} else if (op == "Int") {
digits = (Math.floor(digits.valueOf())).toString()
} else if (op == "√") {
digits = Number(Math.sqrt(digits.valueOf()))
display.newLine("√", digits.valueOf())
} else if (op == "mc") {
memory = 0;
} else if (op == "m+") {
memory += digits.valueOf()
} else if (op == "mr") {
digits = memory.toString()
} else if (op == "m-") {
memory = digits.valueOf()
} else if (op == "backspace") {
digits = digits.toString().slice(0, -1)
display.clear()
display.appendDigit(digits)
} else if (op == "✔") {
window.visible=false
boxCommPos.value=parseInt(digits)
display.clear()
curVal = 0
memory = 0
lastOp = ""
digits = ""
} else if (op == "X") {
window.visible=false
display.clear()
curVal = 0
memory = 0
lastOp = ""
digits = ""
}
// Reset the state on 'C' operator or after
// an error occurred
if (op == "C" || display.isError) {
display.clear()
curVal = 0
memory = 0
lastOp = ""
digits = ""
}
}
Button.qml
// Copyright (C) 2015 The Qt Company Ltd.
import QtQuick 2.0
Item {
id: button
property alias text: textItem.text
property color color: "#eceeea"
property bool operator: false
property bool dimmable: false
property bool dimmed: false
width: 30
height: 50
Text {
id: textItem
font.pixelSize: 48
wrapMode: Text.WordWrap
lineHeight: 0.75
color: (dimmable && dimmed) ? Qt.darker(button.color) : button.color
Behavior on color { ColorAnimation { duration: 120; easing.type: Easing.OutElastic} }
states: [
State {
name: "pressed"
when: mouse.pressed && !dimmed
PropertyChanges {
target: textItem
color: Qt.lighter(button.color)
}
}
]
}
MouseArea {
id: mouse
anchors.fill: parent
anchors.margins: -5
onClicked: {
if (operator)
window.operatorPressed(parent.text)
else
window.digitPressed(parent.text)
}
}
function updateDimmed() {
dimmed = window.isButtonDisabled(button.text)
}
Component.onCompleted: {
numPad.buttonPressed.connect(updateDimmed)
updateDimmed()
}
}