QML item fixed positioning - qt

The mobile devices move the elements up the the keyboard is called, but there are elements that stay in the same position when the device's keyboard appears like the images below.
How can I keep a Qml item fixed in the same position when device's keyboard appears?
I need that the Rectangle with id: principal stays fixed in the same position.
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
Window {
visible: true
property int larguraTela: 360
property int alturaTela: 640
width: larguraTela
height: alturaTela
maximumWidth: larguraTela
maximumHeight: alturaTela
minimumWidth: larguraTela
minimumHeight: alturaTela
title: "OverStatusBar"
Rectangle {
id: principal
width: parent.width
height: parent.height * 0.15
anchors.top: parent.top
color: "orange"
}
Rectangle {
width: parent.width
height: parent.height * 0.85
anchors.top: principal.bottom
clip: true
Rectangle{
id: retangulo1
width: parent.width
height: parent.height * 0.5
anchors.top: parent.top
color: "grey"
}
Rectangle {
id: retangulo2
width: parent.width
height: parent.height * 0.5
anchors.top: retangulo1.bottom
color: "lightgrey"
TextField {
id: campoTexto
width: parent.width * 0.7
height: parent.height * 0.20
anchors.centerIn: parent
inputMethodHints: Qt.ImhDigitsOnly
}
}
}
}

Ok, after a long research about this topic I have concluded that there is no possible solution, at least until now, that doesn't involve a lot of workaround programming to solve that using cross-platform programming. I have tried a bunch of cross-platform languages with no satisfactory solution that could be implemented. The languages I tried were:
QML
Appcelerator (Titanium)
PhoneGap (Cordova)
Native Script
React Native
My conclusion is that if I want do develop native look and feel apps that work as expected and without bugs, I need to do it using the native programming languages, even if I need to develop it twice in different languages. And that is what I am doing from now: XCode and Android Studio.
If someone would like to take a look at a piece of code to start doing it in QML just access the link clicking here:
I have something very hackish and begging for refinement but I think it is going into the right direction :
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
Window {
visible: true
property int larguraTela: 360
property int alturaTela: 640
width: larguraTela
height: alturaTela
maximumWidth: larguraTela
maximumHeight: alturaTela
minimumWidth: larguraTela
minimumHeight: alturaTela
title: "OverStatusBar"
Rectangle {
id: principal
width: parent.width
height: parent.height * 0.15
anchors.top: parent.top
color: "orange"
}
Timer{
id:resetKeyboard
interval: 500
onTriggered: {
Qt.inputMethod.hide();
Qt.inputMethod.show();
unlock.restart();
}
}
Timer{
id:unlock
interval: 500
onTriggered: {
flickable.updateSlideContent = true;
}
}
Flickable{
id:flickable
width: parent.width
height : slideContent ? parent.height * 0.5 : parent.height * 0.85
anchors.top: principal.bottom
clip: true
contentHeight: parent.height * 0.85
contentY : slideContent ? parent.height*0.35 : 0
property bool updateSlideContent : true
property bool slideContent : false
property bool keyboardVisible : Qt.inputMethod.visible
onKeyboardVisibleChanged: {
if (updateSlideContent) {
slideContent = keyboardVisible;
if (keyboardVisible)
{
updateSlideContent = false;
resetKeyboard.restart();
}
}
}
Rectangle {
anchors.fill: parent
Rectangle{
id: retangulo1
width: parent.width
height: parent.height * 0.5
anchors.top: parent.top
color: "grey"
}
Rectangle {
id: retangulo2
width: parent.width
height: parent.height * 0.5
anchors.top: retangulo1.bottom
color: "lightgrey"
TextField {
id: campoTexto
width: parent.width * 0.7
height: parent.height * 0.20
anchors.centerIn: parent
inputMethodHints: Qt.ImhDigitsOnly
}
}
}
}
}

Related

QML TextField placeholderText disappear after push in StackView

//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
StackView {
id: stackView
anchors.fill: parent
initialItem: page1
}
Item {
id: page1
Column {
height: parent.height * 0.2
width: parent.width * 0.5
anchors.centerIn: parent
spacing: height * 0.04
TextField {
height: parent.height * 0.48
width: parent.width
placeholderText: qsTr("Placeholder 1")
}
Button {
height: parent.height * 0.48
width: parent.width
text: qsTr("Next")
onClicked: stackView.push(page2)
}
}
}
Item {
id: page2
Column {
height: parent.height * 0.2
width: parent.width * 0.5
anchors.centerIn: parent
spacing: height * 0.04
TextField {
height: parent.height * 0.48
width: parent.width
placeholderText: qsTr("Placeholder 2")
}
Button {
height: parent.height * 0.48
width: parent.width
text: qsTr("Back")
onClicked: stackView.pop()
}
}
}
}
Hi everybody, I have a problem with the placehoderText property of TextField.
If i do the sequence -> "Next" on page1 -> "Back" on page2 -> "Next" on page1, then page2 is actually displayed but the placeholderText of the TextField is not visible anymore.
Is this a Qt bug or am I doing something wrong?
StackView's goal is not that you tried to use ...
you should use SwipeView if you want prevent destroying items.
for your porpuse you can use a little customized SwipeView:
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
SwipeView {
id: swipView
anchors.fill: parent
interactive: false;
property int stackIndex: -1;
function popIndex(){
return (--stackIndex);
}
function pushIndex(){
return (++stackIndex);
}
Component.onCompleted: {
if(swipView.contentChildren.length>0)
{
swipView.stackIndex=0;
}
}
Item {
id: page1
Column {
height: parent.height * 0.2
width: parent.width * 0.5
anchors.centerIn: parent
spacing: height * 0.04
TextField {
height: parent.height * 0.48
width: parent.width
placeholderText: qsTr("Placeholder 1")
}
Button {
height: parent.height * 0.48
width: parent.width
text: qsTr("Next")
onClicked: swipView.currentIndex=swipView.pushIndex();
}
}
}
Item {
id: page2
Column {
height: parent.height * 0.2
width: parent.width * 0.5
anchors.centerIn: parent
spacing: height * 0.04
TextField {
height: parent.height * 0.48
width: parent.width
placeholderText: qsTr("Placeholder 2")
}
Button {
height: parent.height * 0.48
width: parent.width
text: qsTr("Back")
onClicked: swipView.currentIndex=swipView.popIndex();
}
}
}
}
}
The issue is that by using Items that are parented to the Window like that, they don't get destroyed when they get popped. In the case of page2, that causes it to have a null parent and it resizes to 0x0. That then causes all of the other controls in that page to resize to 0 and that's a problem for the placeholder text (a situation they likely didn't expect).
If instead you use components, they will be sized correctly each time because they are created new at the right size and destroyed as needed.
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
StackView {
id: stackView
anchors.fill: parent
initialItem: page1
}
Component {
id: page1
Item {
Column {
height: parent.height * 0.2
width: parent.width * 0.5
anchors.centerIn: parent
spacing: height * 0.04
TextField {
height: parent.height * 0.48
width: parent.width
placeholderText: qsTr("Placeholder 1")
}
Button {
height: parent.height * 0.48
width: parent.width
text: qsTr("Next")
onClicked: stackView.push(page2)
}
}
}
}
Component {
id: page2
Item {
Column {
height: parent.height * 0.2
width: parent.width * 0.5
anchors.centerIn: parent
spacing: height * 0.04
TextField {
height: parent.height * 0.48
width: parent.width
placeholderText: qsTr("Placeholder 2")
}
Button {
height: parent.height * 0.48
width: parent.width
text: qsTr("Back")
onClicked: stackView.pop()
}
}
}
}
}

How to change the position when the parent is resized?

How do I properly change the x, y of an object so that it changes its position when the parent is resized? There is, I will introduce that if I drag the rectangle to the middle, then when the window is resized, it should remain in the middle. (middle for example only, rectangle can be moved freely)
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
Window {
visible: true
width: 640
height: 480
onWidthChanged: {
block.x -= block.previousWidth - width
block.previousWidth = width
}
onHeightChanged: {
block.y -= block.previousHeight - height
block.previousHeight = height
}
Rectangle {
id: block
color: "red"
width: 50
height:50
x: 100
y: 50
property int previousWidth: 0
property int previousHeight:0
Component.onCompleted: {
previousWidth = parent.width
previousHeight = parent.height
}
MouseArea {
anchors.fill: parent
drag.target: block
}
}
}
I must admit, at first I was not impressed by the question. However, when I thought about it, it represents a very interesting and valid use case. So I would be happy to provide a solution.
Solution
I would approach the problem like this:
Make the frame a child of the background image.
Instead of manually calculating the coordinates, use Item.scale to scale the image, effectively preserving the relative position of the frame with regard to the image.
Example
Here is an example I have prepared for you to demonstrate how the proposed solution could be implemented:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
visible: true
width: 640
height: 480
Image {
anchors.centerIn: parent
source: "alphabet.png"
scale: parent.width/sourceSize.width
Rectangle {
id: frame
width: parent.width/7
height: parent.height/4
border.color: "black"
color: "transparent"
antialiasing: true
MouseArea {
anchors.fill: parent
drag.target: parent
}
}
}
}
Result
The example produces the following result:
Original window
Resized window
The frame is moved
The window is resized again
As I said in my comment, the best solution is anchoring, for example:
Window {
id: root
width: 600
height: 400
title: qsTr("Parent window")
visible: true
flags: Qt.WindowStaysOnTopHint
Grid {
anchors.fill: parent
Repeater {
model: 16
Rectangle {
width: root.width / 4
height: root.height / 4
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
}
}
}
Rectangle {
border {
width: 5
color: "black"
}
color: "transparent"
width: root.width / 4
height: root.height / 4
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: root.width / 4
anchors.bottomMargin: root.height / 4
}
}

Qml Text Size based on Container

I am using Qt Quick to develop an app (Qt 5.8). I have text that appears in multiple places so I created a component to use to display the text. The areas the text can vary in placement and size. How can I adjust my text so that the data displays in 1 line horizontally and all text is the same size if I simply want to display the following?
FLAPS 1
GEAR DOWN
TRIM -1.0
I used Text and was able to get close, however since GEAR DOWN has more characters the text was smaller, than flaps and trim. So I moved on to using Label. Can someone provide better insight on how to have text size based on its container's width or height?
main.qml
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
id: windowRoot
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
height: windowRoot.height * .80
width: windowRoot.width * .80
color: "green"
anchors.centerIn: parent
Rectangle {
id: rect1
opacity: .5
anchors.top: parent.top
anchors.left: parent.left
color: "lime"
border.color: "orange"
height: parent.height * 1/2
width: parent.width * 1/2
TextHolder {
anchors.top: parent.top
anchors.left: parent.left
width: parent.width * 1/4
height: parent.height
}
}
Rectangle {
id: rect2
anchors.top: parent.top
anchors.left: rect1.right
color: "yellow"
border.color: "blue"
height: parent.height * 1/2
width: parent.width * 1/2
}
Rectangle {
id: rect3
anchors.top: rect1.bottom
anchors.left: parent.left
color: "pink"
border.color: "red"
height: parent.height * 1/2
width: parent.width * 1/2
TextHolder {
anchors.top: parent.top
anchors.left: parent.left
width: parent.width * 1/4
height: parent.height * 1/2
}
}
Rectangle {
id: rect4
anchors.top: rect2.bottom
anchors.left: rect3.right
color: "orange"
border.color: "lime"
height: parent.height * 1/2
width: parent.width * 1/2
TextHolder {
anchors.bottom: parent.bottom
height: parent.height * 1/4
width: parent.width * 1/4
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
TextHolder.qml
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.1
Rectangle {
color: "purple"
border.color: "steelblue"
border.width: 3
property color colorOfText: "white"
property real textSize: 48
Item {
id: inputs
property int flapHndl: 1
property int gearHndl: 1
property real trim: -1.0
}
clip: true
ColumnLayout {
anchors.top: parent.top
width: parent.width
height: parent.height
spacing: 5
Label {
id: flapLabel
text: "FLAPS " + inputs.flapHndl
color: colorOfText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: textSize
fontSizeMode: Text.HorizontalFit
Layout.fillWidth: true
}
Label {
id: gearLabel
text: {
if (inputs.gearHndl === 1)
return "GEAR DOWN"
else
return "GEAR UP"
}
color: colorOfText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: textSize
fontSizeMode: Text.HorizontalFit
Layout.fillWidth: true
}
Label {
id: trimLabel
text: "TRIM " + inputs.trim.toFixed(1)
color: colorOfText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: textSize
fontSizeMode: Text.HorizontalFit
Layout.fillWidth: true
}
}
}
Can someone provide better insight on how to have text size based on
its container's width or height?
For evaluating the text width and height we can definitely use QML type TextMetrics and having the metrics we can then attempt to fit the text in. If the text still won't fit we can then try to adjust the font size. For that, some logic might need to be implemented with JavaScript. So, the below code is an example of the "feedback" type of solution.
Rectangle {
property string textToShow
property int widthLimit: 400
onTextToShowChanged: {
while (txtMeter.width > widthLimit) {
txtMeter.font.pixelSize --;
}
}
TextMetrics {
id: txtMeter
font.family: "Courier"
font.pixelSize: 25
text: textToShow
}
Text {
font: txtMeter.font
text: textToShow
}
}
P.S. This is just a sketchy idea and your actual implementation may differ
There is fontSizeMode property of Text
Text {
id: goToParentFolderText
anchors.fill: parent
font.family: fontAwesomeSolid.name
text: "\uf060"
fontSizeMode: Text.Fit
font.pointSize: 100
color: Material.accent
}
I was able to get #Alexander V's answer to work, with a minor change. The outer textToShow property was processing its update before the TextMetrics block was updated (which caused the width calculation to be incorrect). You can fix this issue by triggering onTextChanged inside the TextMetrics blocks instead.
Rectangle {
property string textToShow
property int widthLimit: 400
TextMetrics {
id: txtMeter
font.family: "Courier"
font.pixelSize: 25
text: textToShow
onTextChanged: {
while (txtMeter.width > widthLimit) {
txtMeter.font.pixelSize --;
}
}
}
Text {
font: txtMeter.font
text: textToShow
}
}

How to open ComboBox dropdown menu?

I'm working on a custom ComboBox item with two icons in both sides and a ComboBox in the middle. I want that when any of the icons are clicked the ComboBox dropdown menu opens, but i don't know how to do it.
Here is my code:
// ComboIcon.qml
Rectangle{
color: "#fff"
radius: 10
property alias iconSource: icon.source
property alias comboModel: combo.model
Row{
anchors.fill: parent
Item{
width: parent.width * 0.2
height: parent.height
Image{
id: icon
width: parent.width * 0.7
height: parent.height * 0.7
anchors.centerIn: parent
}
MouseArea{
anchors.fill: parent
// onClicked: combo.??
}
}
ComboBox{
id: combo
width: parent.width * 0.65
height: parent.height
style: ComboBoxStyle{
background:Rectangle {
color: "#fff"
anchors.fill: parent
}
label: Text {
height: parent.height * 0.7
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHLeft
color: "#6186da"
font.family: "SansSerif"
font.pointSize : 20
fontSizeMode: Text.Fit
text: control.currentText
}
}
}
Item{
width: parent.width * 0.15
height: parent.height
Image{
width: parent.width * 0.4
height: parent.height * 0.4
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
source: "../assets/images/combo_arrow.png"
}
MouseArea{
anchors.fill: parent
//onClicked: combo.??
}
}
}
}
I was thinking about using something like combo.clicked() or combo.focus = true, but it doesn't seem to work. Any help would be really appreciated,
thanks.
According to the sources, Combobox has an internal property __popup. Since it is internal, it is not guaranteed to be consistent among different versions of Qt. However, since controls 1 can be considered "done" it is quite unlikely that such a property is going to change in future releases.
Using __popup you can write something like that:
import QtQuick 2.2
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
ApplicationWindow {
visible: true
width: 300
height: 200
RowLayout {
anchors.fill: parent
Image {
fillMode: Image.PreserveAspectFit
Layout.preferredHeight: 64
source: "https://cdn1.iconfinder.com/data/icons/prettyoffice9/128/open-file.png"
MouseArea {
anchors.fill: parent
onClicked: combo.__popup.toggleShow() // <-- showing the popup here!
}
}
ComboBox {
id: combo
model: 3
}
}
}
Finally, a similar approach can be followed for ComboBox from controls 2 where popup is not internal and can be shown by simply changing its visible property, i.e.:
combo.popup.visible = true

Resize ApplicationWindow from Qml

I encountered a bad performance of my implementation of ResizeArea, please help me to speed up...
How I would use :
ApplicationWindow {
id: rootWindow
width: 1280
height: 768
minimumHeight: 768
minimumWidth: 1280
visible: true
flags: Qt.FramelessWindowHint | Qt.CustomizeWindowHint
ResizeArea{
height: parent.height
anchors.left: parent.left
anchors.leftMargin: 0
width: 3
}
}
ResizeArea.qml:
MouseArea {
id: mr
cursorShape: Qt.SizeHorCursor
property int clickPosX
onPressed: {
clickPosX = mouseX
}
onPositionChanged: {
rootWindow.setWidth(rootWindow.width+(mouseX-clickPosX))
}
}
It works, but slowly.
I think implementation with dragItem should be faster, but I don't know how to write it.

Resources