QML DoubleValidator changing decimal to int on focus change - qt

I'm using QML and I need textfields that only accept doubles. I used DoubleValidator for this. However, when I enter, for example a 0.2 in the textfield and hit tab, it will change the value to 2. The same holds for any number formatted as "0.00...0x". When I write any other number after the x, though, it will work correctly. I have no idea why this is and why anyone would want this. What am I doing wrong?

I try this Example and it works well for me :
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: window
width: 640
height: 480
visible: true
title: qsTr("Example")
Rectangle{
id:rect1
y: 140
height: 40
border.width: 2
anchors.rightMargin: 250
anchors.leftMargin: 131
antialiasing: true
anchors.left: parent.left
anchors.right: parent.right
TextInput {
id: textInput
anchors.fill: rect1
font.pixelSize: 18
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
activeFocusOnTab: true
focus: true
validator: DoubleValidator{}
}
}
Rectangle{
id:rect2
y: 200
height: 40
border.width: 2
anchors.rightMargin: 250
anchors.leftMargin: 131
antialiasing: true
anchors.left: parent.left
anchors.right: parent.right
TextInput {
id: textInput2
anchors.fill: rect2
font.pixelSize: 18
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
activeFocusOnTab: true
focus: true
validator: DoubleValidator{}
}
}
Text {
id: text1
x: 51
y: 147
width: 74
height: 27
text: qsTr("Text Input 1")
font.pixelSize: 12
}
Text {
id: text2
x: 45
y: 215
width: 74
height: 25
text: qsTr("Text Input 2")
font.pixelSize: 12
}
}
output:

Paraphrasing my answer from forum.qt.io:
The DoubleValidator's behavior depends on the locale being used.
In some country like France for example, the period (.) is not a decimal marker but just a separator for thousands, millons, etc. The actual decimal marker is the comma (,).
If you want to force your DoubleValidator to use the english locale you can do so for each instance: DoubleValidator { locale: "en"; /* ... */ } or do it for the whole application once by calling QLocale::setDefault before instantiating your QGuiApplication.

Related

How to call data from elsewhere when I click a button in QML

When I click a button in QML, I want the data from another place that I created before to come to the textfields in my table, how can I do it? Can I do this in QML or do I need to create a separate backend cpp file? Can you help me please?
For example this below code is one row of my table
Rectangle{
border.width: 2
border.color: "black"
id:rectangle_mov_mean_nokta_sayisi
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: mainWindow.width/8
Layout.preferredHeight: mainWindow.height/22
Layout.margins: -3
Layout.fillWidth: true
color: row_even
Text{
color:normal_text
id:text_rectangle_mov_mean_nokta_sayisi
text:"Mov Mean Nokta Sayısı"
anchors.centerIn: parent
}
}
Rectangle{
border.width: 2
border.color: "black"
id:rectangle_mov_mean_nokta_sayisi_deger
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: mainWindow.width/8
Layout.preferredHeight: mainWindow.height/22
Layout.margins: -3
Layout.fillWidth: true
color:row_even
TextField {
id:textfield_rectangle_mov_mean_nokta_sayisi_deger
anchors.centerIn: parent
placeholderText: qsTr("")
color:normal_text
}
}
There are 20 of these rectangles. When I click a button, a separate value will be displayed for each text field. I need to create these values elsewhere.
you should read Signal and Slots in QML.
For example :
If you have 3 separate QML files:
In main.qml:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("External Components with signals and slots")
Notifier{
id : notifierId
rectColor: "yellowgreen"
target: receiverId
}
Receiver {
id : receiverId
rectColor: "dodgerblue"
anchors.right: parent.right
}
Component.onCompleted: {
notifierId.notify.connect(receiverId.receiveInfo)//Connect signal to slot
}
}
and in Receiver.qml :
import QtQuick 2.12
Item {
property alias rectColor: receiverRectId.color
width: receiverRectId.width
height: receiverRectId.height
function receiveInfo( count){
receiverDisplayTextId.text = count
console.log("Receiver received number : "+ count)
}
Rectangle {
id : receiverRectId
width: 200
height: 200
color: "red"
Text {
id : receiverDisplayTextId
anchors.centerIn: parent
font.pointSize: 20
text : "0"
}
}
}
and in Notifier.qml:
import QtQuick 2.12
Item {
property alias rectColor: notifierRectId.color
width: notifierRectId.width
height: notifierRectId.height
property int count: 0
signal notify( string count)//Declare signal
property Receiver target : null
onTargetChanged: {
notify.connect(target.receiveInfo)
}
Rectangle {
id : notifierRectId
width: 200
height: 200
color: "red"
Text {
id : displayTextId
anchors.centerIn: parent
font.pointSize: 20
text : count
}
MouseArea{
anchors.fill: parent
onClicked: {
count++
notify(count)
}
}
}
}
you can see that by using signals and slots you can send data from Notifier.qml to Receiver.qml.

How to use own objects in ColumnLayout in QML?

I would like to produce a table where in every Row is a Text() and a ComboBox(). I want the comboboxes are aligned right and also the left side of the text labels something like that:
I have the main qml:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Window {
id: wind
width: 640
height: 480
visible: true
title: qsTr("Public Transport Searcher")
property string oz: "Odjezdová zastávka"
property string pz: "Příjezdová zastávka"
property string co: "Čas odjezdu"
Rectangle{
id: rect
x: wind.width/16
implicitHeight: parent.height/3*2
implicitWidth: wind.width/8*7
anchors.right: parent.right
anchors.left: parent.left
anchors.margins: 20
radius: 5
color: "lightblue"
ColumnLayout{
id: cl
spacing: 30
width: parent.width
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 20
anchors.fill: parent
Row{
id: r1
Layout.alignment: Qt.AlignTop
//Layout.alignment: Qt.AlignTop
Layout.margins: 15
Text{
id: r1t1
text: "Vyhledávač jízdních řádů"
font.pointSize: 16
font.bold: true
}
}
Line{
id: r2
tt2: oz
Layout.alignment: Qt.AlignLeft
//anchors.top: r1.bottom
}
Line{
id: r3
tt2: pz
Layout.alignment: Qt.AlignLeft
}
Line{
id: r4
tt2: co
Layout.alignment: Qt.AlignLeft
}
}
}
}
And a separate Line.qml item:
import QtQuick 2.15
import QtQuick.Controls 2.12
Item {
property string tt2: "v"
Text{
id: txt
text: tt2
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
}
ComboBox{
id: cb
anchors.verticalCenter: parent.verticalCenter
//anchors.fill: parent
anchors.left: txt.right
}
}
Now it runs but the all Rows are overwritting in the top left corner.
I know that I could use the GridLayout but I want to take advantage from the own objects for one row (in case I have much such rows) to avoid copy paste technic and initialise every object of the row separate.
Could you show me please how to do that in an elagant way?
The problem is that your Line items do not have any implicit size which the ColumnLayout can read from. That is, the Line's base is just an Item whose default implicitHeight and implicitWidth are both 0 - so the ColumnLayout renders them improperly. You have several options.
One option is to add implicitHeight/implicitWidth (or Layout.preferredWidth/Layout.preferredHeight) to your Line's Item:
import QtQuick 2.12
import QtQuick.Controls 2.12
Item {
implicitHeight: 30
implicitWidth: parent.width
property string tt2: "v"
Text{
id: txt
text: tt2
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
}
ComboBox{
id: cb
anchors.verticalCenter: parent.verticalCenter
//anchors.fill: parent
anchors.left: txt.right
}
}
A different way of accomplishing this would be to change the base of the Line to a RowLayout (and remove the interior anchors which would conflict):
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
RowLayout {
property string tt2: "v"
Text {
id: txt
text: tt2
Layout.preferredWidth: 200 // to align ComboBoxes, all text must have same width
// Layout.fillWidth: true // a different option for aligning ComboBoxes
}
ComboBox {
id: cb
}
}

QML - Using ListView with dynamically generated ListElement

I have this QML with the ListView:
import QtQuick 2.0
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.0
import smah.light 1.0
import smah.zone 1.0
Page {
id: page
property var lights: ({})
property var lightNames: ([])
title: "Device control"
ListView {
id: lightList
anchors.fill: parent
model: listModel
delegate:
Rectangle{
width: lightList.width
height: lightList.height / 8
}
}
ListModel {
id: listModel
dynamicRoles: true
Component.onCompleted: {
listModel.clear()
for (var i=0; i<lights.length; i++) {
var component = Qt.createComponent("LightControls.qml",listModel)
listModel.append(component.createObject(lightList, {light_name: lights[i].getName }))
}
}
}
}
The LightControls.qml is:
import QtQuick 2.0
import QtQuick.Controls 2.5
import smah.light 1.0
Rectangle {
id: rectangle
property int light_type: 0
property int light_id: 0
property var light_name: "_DEF"
width: parent.width
height: 50
color: "#040000"
Text {
id: txtName
color: "#fefdfd"
text: qsTr(light_name)
anchors.left: parent.left
anchors.leftMargin: 15
anchors.top: parent.top
anchors.topMargin: 8
font.pixelSize: 20
}
Slider {
id: slider
x: 179
y: 10
width: 302
height: 22
value: 0.5
}
Text {
id: txtValue
x: 517
width: 45
height: 15
color: "#ffffff"
text: qsTr("Text")
anchors.top: parent.top
anchors.topMargin: 8
font.pixelSize: 20
}
Button {
id: button
x: 694
y: 10
text: qsTr("Button")
}
}
I want a clean scrollable list with each of these items generated shown in it. I've looked at using a Repeater instead of the list, but I'll have more elements in the list than are desired on the screen. When running the program, everything is garbled into a single incoherent mess:
There are a few larger issues with your code:
You're trying to add a visual item to a ListModel, which expects ListElement objects. You can use append() to add rows to a ListModel.
Your root delegate item is a Rectangle, which doesn't manage the layout of its children. Use a RowLayout or Row instead.
Your delegate should be delegate: LightControls {}.

Qml virtual keyboard key press

I was able to show the virtual keyboard using the below code.
import QtQuick.VirtualKeyboard 2.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello KeyBoard")
InputPanel {
id: inputPanel
z: 89
y: 0
anchors.left: parent.left
anchors.right: parent.right
}
}
How can I get the pressed 'keys' from the InputPanel.I dont need to display the keys in TextField.

QML ListView with sections representing first letter of model's name role - sections are not visible

I have QML ListView, which shows customers from database via UeCustomerModel. Customers are sorted in model via MySQL statement. All works fine, but now I want to add sections into ListView, so the customers are sorted in sections by first letter criteria. Here is my ListView:
ListView
{
id: ueCustomersListView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignBottom
Layout.margins: 8
clip: true
spacing: 8
delegate: UeCustomerSelectorDelegate
{
ueParamWidth: ueCustomersListView.width
ueParamHeight: 128
ueParamImage: "image://ueCustomerModel/"+model.ueRoleImage
ueParamName: model.ueRoleCustomerName
ueParamTaxId: model.ueRoleCustomerTaxId
ueParamCurrentDebt: model.ueRoleCustomerCurrDebt
ueParamMaxDebt: model.ueRoleCustomerMaxDebt
} // delegate
section.property: model.ueRoleCustomerName // HERE RUNTIME ERROR OCCURS
section.criteria: ViewSection.FirstCharacter
section.delegate: UeCustomerSelectorSectionDelegate
{
ueParamWidth: ueCustomersListView.width
ueParamHeight: 128
ueParamName: section
} // section.delegate
Component.onCompleted:
{
model=ueCustomerModel;
} // Component.onCompleted
} // ListView
and here is section delegate:
import QtQuick 2.5
import QtQuick.Layouts 1.1
Rectangle
{
property int ueParamWidth
property int ueParamHeight
property string ueParamName
width: ueParamWidth
height: ueParamHeight
color: "#4682b4"
antialiasing: true
smooth: true
RowLayout
{
anchors.fill: parent
anchors.margins: 8
spacing: 8
Text
{
color: "#ffffff"
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter
antialiasing: true
text: ueParamName
font.family: "Courier"
font.bold: true
font.pointSize: 12
clip: true
textFormat: Text.RichText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
} // Text
} // RowLayout
} // Rectangle
Now, when ListView is shown, there are no sections visible. What did I miss, i.e., how do I correct section.property: model.ueRoleCustomerName statement to get alphabetical letters from customers (A, B, C, ...). I want ListView to section delegates according to Customer Name (delivered from database via model) first letter. Also, in mentioned line of code, I get QML runtime error Unable to assign [undefined] to QString. Why?
P.S.: model works perfectly (is fast, can search accross customers using TextField), I've tested it 5 times.
According to user sk2212's hint, I've upgraded the code with:
section.property: "ueParamName"
section.criteria: ViewSection.FirstCharacter
section.delegate: UeCustomerSelectorSectionDelegate
{
ueParamWidth: ueCustomersListView.width/2
ueParamHeight: ueCustomersListView.height/4
ueParamName: model.ueRoleCustomerName.subString(0,1)
} // section.delegate
and here is Section delegate:
import QtQuick 2.5
import QtQuick.Layouts 1.1
Rectangle
{
property int ueParamWidth
property int ueParamHeight
property string ueParamName
width: ueParamWidth
height: ueParamHeight
color: "#4682b4"
antialiasing: true
smooth: true
RowLayout
{
anchors.fill: parent
anchors.margins: 8
spacing: 8
Text
{
color: "#ffffff"
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter|Qt.AlignVCenter
antialiasing: true
text: ueParamName
font.family: "Courier"
font.bold: true
font.pointSize: 12
clip: true
textFormat: Text.RichText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
} // Text
} // RowLayout
} // Rectangle
Still does not work.
You have to use the section.property as a model data element:
delegate: UeCustomerSelectorDelegate
{
ueParamWidth: ueCustomersListView.width
ueParamHeight: 128
ueParamImage: "image://ueCustomerModel/"+model.ueRoleImage
ueParamName: model.ueRoleCustomerName
ueParamTaxId: model.ueRoleCustomerTaxId
ueParamCurrentDebt: model.ueRoleCustomerCurrDebt
ueParamMaxDebt: model.ueRoleCustomerMaxDebt
alphabet: model.ueRoleCustomerName.substring(0,1)
} // delegate
section.property: "alphabet"

Resources