How to programmatically press QML Button? - qt

I am building a dialog in QML. I have some TextField, but I'd like that if the user presses enter (accepted signal is emitted), the id: okButton is pressed, actually activating it visually for a moment.
I see that the pressed property is read only.
Thanks!

You can simply call clicked() signal for simulating button press:
Keys.onReturnPressed: {
clicked()
event.accepted = true
}

You can make it checkable for a short duration while you emulate the click with the checked property:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
Timer {
id: timer
running: true
repeat: true
interval: 100
onTriggered: {
button.checked = false;
button.checkable = false;
}
}
Row {
TextField {
anchors.verticalCenter: parent.verticalCenter
onAccepted: {
button.checkable = true;
button.checked = true;
timer.start();
}
}
Button {
id: button
text: "Submit"
anchors.verticalCenter: parent.verticalCenter
}
}
}
From the documentation for the accepted() signal of TextField:
This signal is emitted when the Return or Enter key is pressed.

Related

QML TextArea onEditingFinished On Enter

The QML TextArea inherits onEditingFinished From TextEdit where it is triggered on losing focus or an enter/return press. (assuming no input validation)
However one cannot trigger onEditingFinished from a TextArea with Enter unlike for TextEdit as it is captured for a line break.
Additionally in a window with a single field it can be a unintuitive to remove focus from the TextArea as background and most other Controls don't accept focus so the user has to click off the window or clicking the menu bar.
How can I improve the user experience for triggering actions once they have edited a multiline string input field? Is linebreaks inputted with Ctrl+Enter, with editing completion on Enter an option, and if so how would this be implemented?
Here is the example QML of this scenario:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
Window {
visible: true
width: 640; height: 480
title: qsTr("Hello World")
Column {
TextArea {
implicitHeight: 200
placeholderText: qsTr("Enter description")
onEditingFinished: console.log("Editing complete")
}
Label {text: qsTr("Label")}
}
}
You can override the Return key press event and handle it however you want. If you want to use the Ctrl+Return, check the modifiers property in the event.
TextArea {
implicitHeight: 200
placeholderText: qsTr("Enter description")
onEditingFinished: console.log("Editing complete")
Keys.onReturnPressed: {
if (event.modifiers & Qt.ControlModifier) {
// Ctrl+Return
editingFinished();
}
else {
// Ignore other cases
event.accepted = false;
}
}
}
Or if you want to use the Return key without pressing Ctrl, then you can simply do this:
TextArea {
implicitHeight: 200
placeholderText: qsTr("Enter description")
onEditingFinished: console.log("Editing complete")
Keys.onReturnPressed: {
editingFinished();
}
}
You can do it by handling the simple ReturnPressed and ctrl+ReturnPressed or Shift+ReturnPressed event by yourself.
In the code below I've used Shift+ReturnPressed for new line:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
Window {
visible: true
width: 640; height: 480
title: qsTr("Hello World")
Column {
TextArea {
id: text_area
implicitHeight: 200
placeholderText: qsTr("Enter description")
Keys.onReturnPressed: {
if(Qt.ShiftModifier)
console.log("Editing complete")
else {
text += '\n'
text_area.cursorPosition = text_area.length
}
}
}
Label {text: qsTr("Label")}
}
}
Based on the answers by Jarman (https://stackoverflow.com/a/69723941/1581658) and Farshid616 (https://stackoverflow.com/a/69724074/1581658) I came up with this
TextArea {
implicitHeight: 200
placeholderText: qsTr("Enter description")
onEditingFinished: console.log("Editing complete")
Keys.onReturnPressed: {
if(event.modifiers & Qt.ControlModifier) {
insert(cursorPosition, "\n")
}
else {
editingFinished()
}
}
}
This specifically allows for a newline to be inserted at the current cursor when Ctrl+Enter is pressed, and for editingFinished to be called when a non-modified Enter is pressed

How to give sleep in qml

When I press the button now it instantly goes to the next page. Is it possible to give this loading.gif a sleep of 5 seconds?
I have tried to give it a duration: 5000 but then it gives an error
---- FULL CODE UPDATED ----
Login.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.15
Component
{
Rectangle
{
Rectangle
{
anchors.fill: parent
// Timer for Creating delay
Timer
{
id: timer
}
function delay(delayTime,cb)
{
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
ColumnLayout
{
// Some other items.
Button
{
onClicked:
{
backend.inloggen(email.text, wachtwoord.text, dropdown.currentText)
delay(5000, function()
{
loading_container.visible = true
})
stack.push(btnHomepage)
}
}
Rectangle
{
id: loading_container
visible: false
AnimatedImage
{
source: "./images/loading.gif"
}
}
}
}
}
}
Error: Login.qml:170: ReferenceError: delay is not defined
Sadly updating the the QtQuick nad QtQuick.controls update wasn't the solution
you can create delays by using Timer here is your code, I add one function that creates delay it gets duration like 5000 means 5 seconds, and one function that will be connected to Timer.
This function acts like a singleshot.
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
// Timer for Creating delay
Timer {
id: timer
}
function delay(delayTime,cb) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle
{
id: loading_container
anchors.fill: parent
color: "#d71616"
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 60
visible: false
}
Button {
id: button
x: 0
y: 0
width: 151
height: 62
text: qsTr("Click me ")
onClicked:
{
delay(5000, function() {
loading_container.visible = true
})
}
}
}
As you update the question, Try this :
Component encapsulated QML types with well-defined interfaces.
the way that you use it is wrong.
The way that you use Function in your program is also wrong.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
Item {
width: 640
height: 480
Timer
{
id: timer
}
function delay(delayTime,cb)
{
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle
{
anchors.fill: parent
// Timer for Creating delay
// ColumnLayout
// {
// Some other items.
Button
{
onClicked:
{
// backend.inloggen(email.text, wachtwoord.text, dropdown.currentText)
delay(5000, function()
{
loading_container.visible = true
})
// stack.push(btnHomepage)
}
}
Rectangle
{
id: loading_container
visible: false
AnimatedImage
{
source: "what ever is your source path"
}
}
}
// }
}
In your code, the button doesn't have access to the Delay function, hence the reference error you get
Simply move the function to the button and the Timer in the root item

QtQuick button shows outside of dialog

I'm trying to make a customizable single button error message dialog in QtQuick, but when I open the dialog the "Ok" button is shown outside of it:
it looks like this
When I open the dialog again, it works normally, the button is shown at the right place.
Here is a minimal working example :
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Controls 2.4
Window {
visible: true
width: 640
height: 480
Button {
text: "Open Dialog"
onClicked: {
dialog.show("This text can be customized.")
}
Dialog {
id: dialog
standardButtons: Dialog.Ok
title: "Error"
modal: true
function show(txt) {
label.text = txt
open()
}
Label {
id: label
}
}
}
}
I'm using Qt 5.11.3 with QtQuick 2.11, build target is Desktop GCC 64 bits.
Is this a bug? What am I doing wrong?
It seems to be a bug in Qt 5.11.3 or in my installation of it on Linux.
Here is the workaround I used, basically recreating the Dialog from a regular Popup :
import QtQuick 2.0
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
Popup {
x: (parent.width-width)/2
y: (parent.height-height)/2
modal: true
closePolicy: Popup.NoAutoClose
property var title: "Error"
property var msg: ""
function show(message) {
msg = message
open()
}
ColumnLayout {
spacing: 30
Label {
Layout.alignment: Qt.AlignLeft
Layout.preferredHeight: 5
font.bold: true
text: title
}
Label {
text: msg
}
Button {
Layout.alignment: Qt.AlignRight
text: "Ok"
onClicked: {
close()
}
}
}
}

How to keep a single instance of the window?

I have the next QML:
import Qt.labs.platform 1.0
SystemTrayIcon {
visible: true
iconSource: "qrc:/icons/ic_tray.png"
menu: Menu {
MenuItem {
text: qsTr("Settings")
onTriggered: {
// Don't create a new object if it exists, just show
var settings = Qt.createComponent("main.qml")
var form = settings.createObject(this)
form.show()
}
}
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit() // Just hide an existing
}
}
}
How to create main.qml one time only and after just show/hide?
P.S. I'm learning Qt including QtQuick 2 only
Depending on how your application is structured, the best way could be to pass in the window that the tray icon shall control as a property from "further up" your user interface structure.
First, extend your tray icon component and add a "window" property to it:
import QtQuick 2.9
import QtQuick.Window 2.2
import Qt.labs.platform 1.0
SystemTrayIcon {
id: trayIcon
// this property holds the window the tray icon controls:
property Window window
visible: true
iconSource: "qrc:/icons/ic_tray.png"
menu: Menu {
MenuItem {
text: qsTr("Settings")
onTriggered: {
trayIcon.window.show();
}
}
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit() // Just hide an existing
}
}
}
Now, you could instantiate your tray icon e.g. in your main window like this:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: mainWindow
width: 800
height: 600
TrayIcon { window: mainWindow }
}
In this case, the tray icon would control the main window itself; however, you can easily create a single instance of a settings window within the main window and pass that one to the tray icon.
You can create the component in the onCompleted.
SystemTrayIcon {
visible: true
iconSource: "qrc:/icons/ic_tray.png"
menu: Menu {
MenuItem {
text: qsTr("Settings")
property var form
onTriggered: {
form.show()
}
Component.onCompleted: {
// Don't create a new object if it exists, just show
var settings = Qt.createComponent("Test.qml")
form = settings.createObject(this)
}
}
MenuItem {
text: qsTr("Quit")
onTriggered: Qt.quit() // Just hide an existing
}
}
}

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
}
}
}

Resources