Windows QML: Fix hanging Rectangle after changing height of main Window - qt

In Qt Creator I have a QML Window with a "more" Button at the bottom. If one clicks the botton the window expands or decrease, depending on the state.
This works fine with Kubuntu, but with Windows 10 the button stays in the middle, and only the lower button works an next click.
Sceenshoots:
Kubuntu 15.10
~$ qmake --version
QMake version 3.0
Using Qt version 5.4.2 in /usr/lib/x86_64-linux-gnu
Windows 10
C:\Qt\Qt5.5.1\5.5\mingw492_32\bin>qmake.exe --version
QMake version 3.0
Using Qt version 5.5.1 in C:/Qt/Qt5.5.1/5.5/mingw492_32/lib
Minimal Working Example:
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
id: main
visible: true
width: 200
height: 100
maximumHeight: 200
maximumWidth: 200
Rectangle {
id: rectangleMoreButton
height: 40
width: parent.width
color: "#4a4a4a"
border.color: "#ffffff"
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
Text {
id: textMoreButton
text: "more"
color: "#ffffff"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
rectangleMoreButton.state == 'more' ? rectangleMoreButton.state = "" : rectangleMoreButton.state = 'more'
}
}
states: [
State {
name: "more"
onCompleted: {
textMoreButton.text = "less"
main.height = 200
}
},
State {
name: ""
onCompleted: {
textMoreButton.text = "more"
main.height = 100
}
}
]
}
}
Question:
How could I update the position the "more"/"less" Rectangle button after changing the height of main Window in QML to solve this problem? Is there a way for a force update or repainting the window if the height changes?
Edit for Workaround:
I found a Workaround to fix the hanging Button in Windows: Add a timer, which runs only once with a millisecond time offset after the resizing of the window:
Timer {
id: timerUpdateMoreButton
interval: 1
onTriggered: {
rectangleMoreButton.y = main.y
timerUpdateMoreButton.running = false
}
}
and for the "more" state, the timer has to activated:
timerUpdateMoreButton.running = true

Related

QML Progress Bar doesn't move

I am using QT v5.12.6 and in my application i am planning to use Progress Bar during application bootup for around 15secs. In this 15secs operations like:
QML components creation.
connection with the server.
Other bootup operations will be running in the background.
Once, all the bootup operation is done i will hide my splash screen which is just a Rectangle which includes Loading text with a progress bar. For this 15 secs i will be incrementing the progress bar but the progress bar doesn't increment/move for some 10 secs. It looks like it is hanged, but if i use a busy indicator it starts to rotate. Unfortunately, i can't use busy indicator component as i need a look and feel like a progress bar.
My application runs on a embedded platform which has low end processor and very less RAM speed. I am assuming this problem is due to the Load on the UI as many components is getting created.
Is there any difference between busy indicator and Progress bar and also any suggestions on how to handle UI load on the bootup ?
Edit 1: Added an example. I have tried my level best to mimic the problem. In this example both the busyindicator and Progress bar is getting stuck for sometime. But in the embedded device Busy indicator works but no idea how. After running the application Please click on Click Me button.
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.3
Window {
property int pbValue:0
visible: true
width: 500
height: 400
title: qsTr("Hello World")
Rectangle{
id: mySplashScreen
anchors.fill: parent
ProgressBar{
id: pBar
height: 20
width: parent.width
anchors.bottom: parent.bottom
from:0
value : pbValue
to:30
}
BusyIndicator{
anchors.right: parent.right
running: (pbValue < pBar.to +1)
}
Button{
text: "click me"
onClicked: {
//Create component equivalent to my application which has "n"
//number of components like buttons, combobox, chart view etc.
//Here just creating the rectangle more number of times.
for(var i = 0 ; i < 15000 ;i++) //HINT : Increase/decrease the value if problem is not seen
{
var comp = mycomp.createObject(mySplashScreen)
}
}
}
}
Timer{
id:timer
interval: 250
running: (pbValue < pBar.to +1)
onTriggered: {
pbValue += 1;
}
}
Component{
id:mycomp
Rectangle{
width: 200
height: 200
color: "green"
}
}
}
Move your object creation code into a separate Timer with a small interval, and rather than creating all of the objects at once, create them maybe 50 at a time every 25 MS or something.
This will allow for the main event loop to process other things like the animations for busy indicator while its loading.
Here's one way to go about implementing this
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.3
Window {
property int pbValue: 0
visible: true
width: 500
height: 400
title: qsTr("Hello World")
Rectangle {
id: mySplashScreen
anchors.fill: parent
ProgressBar {
// changed handling of progress bar
id: pBar
height: 20
width: parent.width
anchors.bottom: parent.bottom
from: 0
value: compList.length // bind this value
to: 15000
}
BusyIndicator {
anchors.right: parent.right
running: (pbValue < pBar.to + 1)
}
Button {
text: "click me"
onClicked: {
timer.running = true
}
}
}
property var compList: [] // created property to store all created components to track what has been done
Timer {
id: timer
interval: 25
running: false
repeat: true
onTriggered: {
for (var i = 0; i < 50; i++) {
var comp = mycomp.createObject(mySplashScreen) // moved component into timer
compList.push(comp) // added component to huge list of components for tracking
}
pbValue = compList.length
if ((pbValue >= 15000)) {
timer.running = false
console.log("All components completed")
}
}
}
Component {
id: mycomp
Rectangle {
width: 200
height: 200
color: "green"
}
}
}

get cursor position in WebEngineView qml

I have a program in Qt and a WebEngineView in it .I want to when my user clicked on a inputbox in webEngine a keyboard have been loaded and the inputbox get its contents from my keyboard (i wrote my own keyboard) but i can't do it .i try codes in bellow but don't work
WebEngineView {
anchors.fill:parent
id:webEng
url: "https://example.com"
visible: true
MouseArea {
id : mousearea
anchors.fill: parent
onClicked: {
mykeyboard.visible=true;
}
}
}
This is not a complete answer but this code could help:
import QtQuick 2.10
import QtWebView 1.1
import QtQuick.Controls 1.4
import QtWebEngine 1.7
Item {
width: 1280
height: 720
WebView { // or WebEngineView {
id: webview
width: 1280
height: 720
url: "http://google.com"
visible: true
onLoadingChanged: {
if (loadRequest.status === WebView.LoadSucceededStatus) {
console.log("Loaded!!")
webview.runJavaScript('
var input = document.getElementById("lst-ib");
input.addEventListener("click", function() {
alert("Clicked!");
});
'
)
}
}
}
Rectangle {
id: myDummyKeyboard
anchors.bottom: parent.bottom
width: parent.width
height: 100
color: "gray"
visible: true
border.width: 20
Button {
anchors.centerIn: parent
text: "Dummy"
onClicked: {
webview.runJavaScript('document.getElementById("lst-ib").value += "' + text + '"');
}
}
}
}
The part in the WebView (or WebEnginView) allows to display an alert when the input is clicked. But, something is missing, to link it to a QML handler. The solution is maybe to use WebChannel or maybe WebEngineScript as said by #folibis in the comments.
The part defined by myDummyKeyboard allows to add a string into the input when the user is clicking the button in the rectangle (fake keyboard).

How should I start QML files?

I have 4 QML files: MainMenu.qml, AppArea.qml, Result.qml and main.qml.
When my app starts, I want to see first page as MainMenu.qml fullscreen. There is a button (on MainMenu.qml) to start AppArea.qml. When I click the the button, I want to start AppArea.qml as fullscreen new window.
There is a button (on AppArea.qml), when I click that button, I want to show Result.qml but I want to see Result.qml on AppArea.qml, I mean when Result.qml come outs, AppArea.qml will not disappear but Result.qml will appear on AppArea.qml.
There is a button on Result.qml. When I click the button, the Repeater in AppArea.qml will regenerate, because maybe model of Repeater changing like 1, 2, 3, 4.... There is a button on AppArea.qml, when I click the button, I want to open MainMenu.qml as a fullscreen new window like AppArea.qml.
Actually you can think basic: My app is a game like this:
How way should I choose for these jobs?
In addition to the mentioned post, in your case you are using the component from qml file, so you need to load the component first, your main.qml can be like this:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
id: mainWindow
title: "Main window"
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Loader{
id: mainMenuLoader
}
Component.onCompleted: {
mainMenuLoader.source="mainMenu.qml"
var mainMenu = mainMenuLoader.item.createObject(mainWindow);
mainWindow.hide()
}
}
and your mainMenu.qml can look like this:
import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Controls 2.2
Component {
id: mainMenu
Window {
id:mmenu
title: "Main Menu"
width: 600
height: 600
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Loader{
id: appAreaLoader
}
Text {
text: "This is mainMenu"
}
Button{
id: loadAppArea
anchors.centerIn: parent
text: "Start Game"
onClicked: {
appAreaLoader.source="appArea.qml"
var appArea = appAreaLoader.item.createObject(mainMenu);
hide()
}
}
}
}
you will need to do the same for successive windows ...etc.
While for result, you need to use a MouseArea:
appArea.qml:
Component {
id: appMenu
Window {
id:appMenuWindow
title: "App Menu"
width: 600
height: 600
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Loader{
id:anotherLoader
visible: true
anchors.left: appMenuText.left
anchors.top: appMenuText.bottom
width: parent.width/3
height: parent.height/3
}
Text {
id: appMenuText
text: "This is App Area"
anchors.centerIn: parent
}
Button{
id: loadResult
text: "Show Result"
onClicked: {
anotherLoader.source = "result.qml"
anotherLoader.visible=true
}
}
Button{
anchors.right: parent.right
id: loadMainMenu
text: "Open main Menu"
onClicked: {
hide()
//mmenu.show()
anotherLoader.setSource("main.qml")
}
}
}
}
result.qml:
Rectangle{
color: "green"
Text {
anchors.centerIn: parent
id: resultxt
text: qsTr("This is result, Click to close")
}
MouseArea {
anchors.fill: parent
onClicked: { anotherLoader.visible = false
}
}
}

How to auto-hide ApplicatioWindow menuBar?

I'd like to have an ApplicationWindow have an auto-hiding menuBar, which shows up when mouse cursor is positioned on the uppermost part of the window. Is this possible in QML?
PS: I'm using Qt 5.3.
Thanks in advance.
You can exploit internal properties, i.e. properties starting with "__". Since they are internal, functionality could break in future releases even if IMO it is unlikely in this case.
By using internal properties you can exploit __contentItem, the graphical container of the MenuBar and animate its properties to achieve the desired result. Here is a possible approach; it works with Qt 5.3/ Qt 5.4/ Qt 5.5 (the ones I could test it on):
ApplicationWindow {
id: app
visible: true
width: 400
height: 300
property real hideValue: 0
Behavior on hideValue {
NumberAnimation {duration: 200}
}
menuBar: MenuBar {
id: menu
//__contentItem.scale: value // (1)
//__contentItem.opacity: hideValue // (2)
__contentItem.transform: Scale {yScale: hideValue} // (3)
Menu {
id: m1
title: "File"
MenuItem { text: "Open..."
onTriggered: {
hideValue = 0 // hide the bar
}
}
MenuItem { text: "Close"
onTriggered: {
hideValue = 0 // hide the bar
}
}
}
}
Button{
id: b1
anchors.centerIn: parent
text: "CLICK ME!"
width: 100
height: 100
}
MouseArea {
id: ma1
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: menu.__contentItem.implicitHeight
hoverEnabled: true
onEntered: {
hideValue = 1 // show the bar
}
}
MouseArea {
id: ma2
anchors.fill: parent
hoverEnabled: true
z: -1
onEntered: {
m1.__dismissMenu()
hideValue = 0 // hide the bar
}
}
}
Summarizing the code:
Two MouseArea are defined: ma1 which covers the MenuBar and ma2 which fills the ApplicationWindow. The latter has a z negative to be positioned under any other element of the window, inclusing ma1: this way it cannot interfere with events related to any element added (such as the example button b1).
ma1 sets a property called hideValue to 1 whereas ma2 brings it back to 0. The property is used over a visual property of __contentItem (see (1), (2) and (3) in the code) to hide/show the MenuBar. A simple Behaviour over the hideValue property ensures that the transition is smooth.
Internal function __dismissMenu() is used to ensure that an opened Menu is closed when the MenuBar loses focus.
When a MenuItem is triggered the hideValue property is directly reset to ensure correct hiding.
I managed to get some results with this code:
ApplicationWindow {
id: app
MenuBar {
id: menu
Menu {
title: "Menu 1"
MenuItem {
text: "item 1"
}
MenuItem {
action: "item 2"
}
}
}
MouseArea {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 20
hoverEnabled: true
onEntered: {
if (app.menuBar === menu)
app.menuBar = null;
else
app.menuBar = menu;
}
}
}
The change however is abruptly and QML debugging report errors when trying to access null.__contentItem when the bar is hidden. And, of course, there's an absolute size in the code which could cause problems.

Close QT Child Window and open again controls are gone

I’m a newbie, and I’m trying to get a child window to work. I followed after the controls gallery example, and it doesn’t work right, in my opinion. When you click the button to show the child window, it works fine, and if you click the button that says close it does window1.visible = false, which works fine.
However, if instead of clicking the button you close the window using the x box on the window, it destroys the window and if you try to open it again it displays a window, but the controls are missing.
This program initializes the child window before at the beginning of main.qml. It seems to me that if I initialized the window when I actually click the button, that would work, but I can’t figure out how to do it.
Any ideas?
Here's the code sample:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
title: qsTr("Child Window")
width: 640
height: 480
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
Window {
id: window1
width: 200
height: 200
title: "child window"
flags: Qt.Dialog
Rectangle {
color: syspal.window
anchors.fill: parent
Text {
id: dimensionsText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
width: parent.width
horizontalAlignment: Text.AlignHCenter
}
Text {
id: availableDimensionsText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: dimensionsText.bottom
width: parent.width
horizontalAlignment: Text.AlignHCenter
}
Text {
id: closeText
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: availableDimensionsText.bottom
text: "Child Window Test"
}
Button {
anchors.horizontalCenter: closeText.horizontalCenter
anchors.top: closeText.bottom
id: closeWindowButton
text:"Close"
width: 98
tooltip:"Press me, to close this window again"
onClicked: window1.visible = false
}
}
}
Button {
text: qsTr("Open Child Window")
anchors.centerIn: parent
onClicked: {
window1.visible = !window1.visible
}
}
}
If you click on the button in the child window to close it, it works fine. If you click on the x in the corner to close the window, it closes it but next time you open it the control (close window button and text) are not visible.

Resources