I have a Qt QML application written in the QtCreator and I want to add a button that gives users the ability to toggle the window flag 'StayOnTop'. I'm not looking for specifics on how to create a button and all that jazz, im simply looking for help on the function that does the window flag toggles. I know how todo this in Python/Pyside but not QML C++.
For example how do i translate this into my qml application?
def toggle_stay_on_top(self):
if self.stayOpTopAct.isChecked():
# enabled
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
else:
# disable
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint)
I tried using this but the title bar and min/max/close buttons disappeared.
flags: Settings.stayOnTop ? flags | Qt.WindowStaysOnTopHint : flags & ~Qt.WindowStaysOnTopHint
Use a Window in your QML file. There is a property flags that you can use.
Window {
id: root
flags: Qt.Tool // Just to check if the flag isn't removed
visible: true
width: 500
height: 500
Rectangle {
anchors.fill: parent
color: "red"
CheckBox {
id: stayOpTopAct
text: "Stay on top"
onCheckStateChanged: {
if(checked)
root.flags = root.flags | Qt.WindowStaysOnTopHint
else
root.flags = root.flags & ~Qt.WindowStaysOnTopHint
}
}
}
}
Related
I understand that you can set the QML window icon using .setWindowIcon(QIcon) after creating the QGuiApplication object. However I have multiple windows created in QML and I want to set an icon to a window inside from QML for example inside:
Window {
id: settings
width: 300
height: 300
title: qsTr("Settings")
flags: Qt.Window
visible: false
// Set window icon here...
}
Is it possible to do this? I have researched about this and I cannot find anything related to this.
I am writing a small application that is working as follows:
1) I launch the application and I select a robot to which I will connect. See print screen below of the small app:
2) That will lead me to another page where I can actually choose the robot to connect to as shown in the print screen below:
3) Finally after selecting the robot the application brings me back to the initial screen that will show me an additional Button showing the chosen robot.
The problem: I have is that after I choose the robot and I am back to the initial screen and I push the button the color of the button should turn into a (for example) green color and changing the text into (for example) Connecting...
The code I am using is the following for which I am only putting the related part:
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls.Styles 1.4
Page {
property int dialogId: -1
signal selectDialog()
ColumnLayout {
anchors.fill: parent
spacing: 5
Button {
id: button1
text: "Select Robot"
onClicked: selectDialog()
Layout.fillWidth: true
font.pointSize: 20
}
Button {
id: dialogA
text: "FreddieMercury: Connect";
visible: dialogId === 1
Layout.fillWidth: true
font.pointSize: 20
function buttonClick()
{
console.log("Button "+ dialogA.text +" is clicked!")
}
Rectangle {
id: button
color: "red"
width: 96; height: 24; anchors.centerIn: parent
MouseArea {
id: region
anchors.fill: parent;
onClicked: console.log("clicked()")
onPressed: dialogA.color = "green"
onReleased: dialogA.color = "red"
}
Text {
id: st_text
anchors.centerIn: parent
text: "Connecting..."
font.bold: true
font.pointSize: 20
color: "green"
}
}
}
// Other Buttons
}
}
What I tried so far
I went through this source and also this post which I followed. As you can see from the point 3) I am close to the good functioning but there is clearly something I am not doing right.
Also this was useful and in fact I used the MouseArea option exactly from that post.
However I still don't see the whole color extended into the button.
Finally the text changed after the click event happened I included it in the Button as shown and thought that the property text: "Connecting..." was enough to overwrite the existing text but without success.
Please advise on what I am missing that is keeping me from a full working example.
I think the base issue is that you're trying to use examples for QtQuick Controls 1 with QtQuick Controls 2. They're completely different animals and you cannot style the v2 controls using QtQuick.Controls.Styles.
For customizing Controls 2 styles, like Button, see here. I also find it useful to look at the source code for the included controls (they're in your Qt library install folder inside /qml/QtQuick/Controls2/ directory). Though personally I find needing to re-create a whole new Button (or whatever) just to change a color or font is a bit much, especially if I want it to work across all the included QtQuick Controls2 Styles.
An alternative is to "hack" the properties of the built-in Control styles. This certainly has some drawbacks like if you want to be able to reset the control style back to default bindings, you'd have to save the original bindings and re-create them to reset the style. OTOH it beats creating customized controls for each style. YMMV.
Anyway here's an example of what i think you're looking for. This is based on our previous exercise with the buttons. :) Specifically, I just modified the Page1.qml code and the other 2 files are exactly the same as before. In this page I added buttonClick() handler and the Button::onClicked calls to trigger it from each button (and the button texts of course :).
Page1.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.impl 2.12 // for IconLabel
import QtQuick.Layouts 1.12
Page {
property int dialogId: -1;
signal selectDialog()
function buttonClick(button)
{
button.text = qsTr("Connecting to %1...").arg(button.text);
button.enabled = false; // prevent repeat clicks
// If Button has a background Rectangle object then we can set properties on it.
// note: `instanceof` was added in Qt 5.10
if (button.background && button.background instanceof Rectangle) {
button.background.color = "red"; // override style color
button.background.gradient = null; // some styles use a gradient
button.background.visible = true; // some styles may hide it in some situations
}
// Similar with the label element, IconLabel is used by all included QML styles.
if (button.contentItem && button.contentItem instanceof IconLabel) {
button.contentItem.color = "blue"; // override style color
button.contentItem.font.bold = true;
button.contentItem.font.pointSize = 20;
}
}
ColumnLayout {
anchors.fill: parent
spacing: 5
Button {
id: button1
text: "Select"
onClicked: selectDialog()
Layout.fillWidth: true
}
// These buttons should appear only after the user selects the choices on `Page2`
Button {
id: dialogA
text: "Freddie Mercury"
visible: dialogId === 1
Layout.fillWidth: true
onClicked: buttonClick(this)
}
Button {
id: dialogB
text: "David Gilmour"
visible: dialogId === 2
Layout.fillWidth: true
onClicked: buttonClick(this)
}
Button {
id: dialogC
text: "Mick Jagger"
visible: dialogId === 3
Layout.fillWidth: true
onClicked: buttonClick(this)
}
}
}
If you had a customized Button (like in the Qt docs example) then you could still do basically the same thing in buttonClick() but probably w/out worrying about the if (button.background ...) stuff (since you'd be sure your button has valid background/contentItem Items).
A better implementation of a "default" (Style-specific) Button but with custom colors/text properties would involve a subclass which uses Binding and/or Connections QML elements to control the properties and be able to reset them back to the current QtQuick Style defaults.
Here I have a minimal example:
import QtQuick 2.9
import QtQuick.Controls 2.3
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Component.onCompleted: {
menu.open();
}
Menu {
id: menu
Keys.onPressed: {
console.log("pressed")
}
MenuItem {
text: "test"
Keys.forwardTo: [menu]
focus: highlighted
onTriggered: {
console.log("triggered 1")
}
}
MenuItem {
text: "test2"
focus: highlighted
Keys.forwardTo: [menu]
onTriggered: {
console.log("triggered 2")
}
}
MenuItem {
text: "test3"
focus: highlighted
Keys.forwardTo: [menu]
onTriggered: {
console.log("triggered 3")
}
}
}
}
Navigating through Menu Items with keyboard works as expected. But triggering with Enter key doesn't work. Also as a workaround I tried to forward key events to the parent menu item, and it didn't work as well.
The only way to fix it I see right now: place Keys.onReturnPressed to every MenuItem and make it call triggered() signal. But it feels wrong.
Is it a bug of Qt?
What is a right workaround for it?
I'm using Qt 5.10.1
The Menu is not Item, so it could not set into Keys.forwardTo.
The navigation of Menu via the Forward/Backward key is enabled by default, Keys.forwardTo is not necessary.
Why Enter key does not work because to select the MenuItem is using Space key not the Enter key. [↑] and [↓] is for Navigation(focus) and [Space] is for Selection
I think if you want to listen the [Enter] key for the Selection, add Keys.onReturnPressed: triggered(); is the right way.
Update:
The [Enter] key was worked in Qt 5.6 (verified). check the source code. But looks like it is removed in the current version.
How does one display a QtQuick UI fileset (ui.qml and .qml) from a normal QML Window?
To display other QML windows from my parent Window class, the call is, roughly:
var component = Qt.createComponent("SubWindow.qml")
var window = component.createObject(window)
window.show()
I've tried calling both the QtQuickUISubwindow.ui.qml and QtQuickUISubwindow.qml, but neither works.
Are QtQuickUI files not meant to be sub windows?
Window and ApplicationWindow are not of Type Item (or QQuickItem). This however is a requirement for being placed as a root item in a .ui.qml-file as stated in the documentation:
The following features are not supported:
[...]
Root items that are not derived from QQuickItem or Item
So the answer is:
No, you can't use QtQuickUI files neither as windows nor as sub windows.
You can however easily use them within a sub window
// main.qml
Window {
id: root
width: 800
height: 600
visible: true
Loader { // creates my sub window without JS
id: winLoader
active: false // Change to create the window.
sourceComponent: Window {
width: srcLoader.item ? srcLoader.item.width : 0
height: srcLoader.item ? srcLoader.item.height : 0
visible: srcLoader.item
Loader {
id: srcLoader
source: "QtQuickUISubwindow.ui.qml" // Your ui.qml-file *here*
active: true
}
onClosing: winLoader.active = false
}
}
Button {
text: "Show sub window!"
onClicked: winLoader.active = true
}
}
This code has not been tested by me. Maybe I'll do so later once I have access to a Qt machine. How to initialize multiple windows with a repeater and a ListModel you can find here: https://stackoverflow.com/a/47018205/2056452
You might pass the source of the srcLoader to the model, and read it from there if you want to open multiple different windows.
You can ofc modify the QtQuickUISubwindow.qml-file and add a Window or ApplicationWindow of the appropriate size as the root element. Then you can create everything as you used to do, using JS - and hope that the garbage collector plays nicely.
I'm trying to implement a keyboard shortcut control for my qml application. I know there's the possibility to do that with an Action element, but I don't want menus and toolbars which are then mandatory to use.
That's why I'm approaching this topic with keyboard events. For this, I need to have the element performing the action to be in focus. But my goal is a global shortcut control, so theoratically I'd need to have all the elements in question in focus.
I found the FocusScope type in the documentation, but I'm not sure if this is what I need.
Does it mean that the focus of nested FocusScopes 'slides' through to the last element that's not a FocusScope and acquiring focus manually with focus: true thus only this last element holding focus? Or do all the elements on the way down the slide that acquire focus have the activeFocus property set?
Is this the right approach or would I need something else?
Focus in Qt Quick is a mess in my opinion. It always confuses me and I end up hacking around it with forceActiveFocus(). I'd recommend the new Shortcut type:
Shortcut {
sequence: StandardKey.Quit
context: Qt.ApplicationShortcut
onActivated: Qt.quit()
}
With the context property, you can choose whether you want the shortcut to apply to the current window or the entire application.
The motivation for this type can be seen in the comments of patch set 5:
Shortcut aims to supersede Action. I want to kill the latter in the future because...
compare the actual user code: http://cutebin.fi/prwznhkbo
look at the amount of "action" related expressions all around BasicButton.qml
IMHO the whole concept doesn't quite fit mobile/embedded or QML
Action was a frequently requested feature. Now that they have it, the frequent questions are "how to use a different icon/text" or "how to know the source that triggered an action". Both are contradicting the sole purpose of Action, and neither "problem" would exist if they just wrote simpler QML code in the first place, as illustrated by the example snippet. :)
Evidently the most usable part of Action is the shortcut feature. Those who need shortcuts are not happy that they need to use Action, because "what's up with all this other stuff, I just want a shortcut".
Maybe there are different ways of achieving this, but the way I know is the following one.
The idea is to have an Item which controls the key events you need to handle.
I'll explain myself with an example. As you will see, if we have input widgets (i.e. TextInput) we have to implement a mechanism to return the input to our Item in order to process again the keyboard events. In this example, the Qt.Key_Escape key will be used to set the focus back.
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
id: mainwindow
title: qsTr("Hello")
width: 640
height: 480
visible: true
Item {
anchors.fill: parent
focus: true
Keys.onPressed: {
if ( (event.key === Qt.Key_Q) && (event.modifiers & Qt.ShiftModifier) ) {
rect.blue()
} else if ( (event.key === Qt.Key_W) && (event.modifiers & Qt.AltModifier) ) {
rect.red()
} else if ( (event.key === Qt.Key_E) && (event.modifiers & Qt.AltModifier) ) {
text.text = 'Key Alt+E was pressed'
}
}
Rectangle{
id: rect
width: 100
height: 100
color: "black"
function blue() {color = "blue"}
function red() {color = "red"}
}
Text {
id: text
anchors.centerIn: parent
font.pointSize: 20
}
TextInput {
id: textinput
anchors.top: text.bottom
text: "sample text"
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
console.log('Key Escape was pressed');
parent.focus = true;
}
}
}
}
}
Edit #1: #Mitch suggested to use the Shortcut QML Type. If you can use it (it's available since Qt 5.5), the code will be slightly different. Anyway, you need also to set the focus to the main app in some cases depending on the shortcut sequences implemented. For example, if we're typing text, Shift+Q doesn't have effect in this example. We need to press Escape first.
import QtQuick 2.5
import QtQuick.Controls 1.3
ApplicationWindow {
id: mainwindow
title: qsTr("Hello")
width: 640
height: 480
visible: true
Shortcut {
sequence: "Shift+Q"
onActivated: rect.blue()
context: Qt.ApplicationShortcut
}
Shortcut {
sequence: "Alt+W"
onActivated: rect.red()
context: Qt.ApplicationShortcut
}
Shortcut {
sequence: "Alt+E"
onActivated: text.text = 'Key Alt+E was pressed'
context: Qt.ApplicationShortcut
}
Item {
anchors.fill: parent
Rectangle{
id: rect
width: 100
height: 100
color: "black"
function blue() {color = "blue"}
function red() {color = "red"}
}
Text {
id: text
anchors.centerIn: parent
font.pointSize: 20
}
TextInput {
id: textinput
anchors.top: text.bottom
text: "sample text"
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
console.log('Key Escape was pressed');
parent.focus = true;
}
}
}
}
}
Much like Mitch, I found focus to be a mess in QML, much like many other aspects of it.
I ended up implementing my own "active focus / selection" scheme. Basically I keep a list of item pointers as my "active selection", I have the keyboard focus fixed at a single item acting as an event dispatcher, and it redirects keyboard events to all items in the active selection list. I still use QML's MouseArea to manage the selected items.