how to regenerate an UI stochastically in QML using a Button on the interface? - qt

I am working on the following QML framework for music apps user-interface prototyping:
https://github.com/tiagmoraismorgado/TMM_QML_UI_UX_FRAMEWORK_WIP in the file instiationTest, i need to add a type Button1_1 and then use it to regenerate the whole gui based on combostochasticselector.
i know i have to instantiate the randomPicking() function, from the instantiationtest file, on top of the mouseArea Pressed statement of Button1_1, but i am not being able to do so.
if anyone could provide me any insight i would be pretty thankful
here is the code of the main file
(...)
Window {
id: root
width: Screen.width
height: Screen.height
visible: true
visibility: "FullScreen"
title: qsTr("instantiationTest")
color: "black"
CombosStochasticSelector {}
}
on the combostochasticselector, you can see the following:
Item {
property var model: model1
anchors.fill: parent
id: randomMIDIkeyboardSelector;
property var random: 0;
function randomSelection(min, max) {(...)}
function createMidiKeyboard(itemToBeInstantiated) {
var component = Qt.createComponent(itemToBeInstantiated)
if (component.status === Component.Ready) {
var midiKeyboard = component.createObject(randomMIDIkeyboardSelector, {model: model});
}
else if (component.status === Component.Error) {
}
}
function randomPicking() {
random = parseInt(randomSelection(1, 13));
if(random == 1) {createMidiKeyboard("./../_Combos/Combo1.qml");}
(...)
return random;
}
Component.onCompleted: {
randomPicking();
}
}
on the Button1_1 you can see the following:
import QtQuick 2.6
QMLOpenGLToggleButtonPrimitive {}
It instantiates a press released kind of button made out of Rectangle QML Primitives
kind regards
Tiago

Related

In QML, the Loader freezes the UI when loading large/time-consuming objects

There are several questions on this subject that are unrelated to my question and They did not produce any results for me.
Imagine I have a splash screen with AnimatedImage in QML that I want to display when my heavy components are loading in the background, so I use a Loader to load assets in background, but when the loader starts loading my UI freezes(i.e. that AnimatedImage), I can see that BusyIndicator not freezes.
I have provided the full source code in the github repository so that you may test it more easily.
my questions are:
Do Loaders really run in the background (for example, if I'm trying to connect to a server in my constructor, can Loader handle this situation or do I have to run it in another thread)?
How should such scenarios be handled so that I do not see any glitches?
window.qml
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts
Window {
id:mainWindow
y:100
width: 640
height: 480
visible: true
flags: Qt.FramelessWindowHint
//splash screen
Popup {
id: popup
width: mainWindow.width
height: mainWindow.height
modal: false
visible: true
Overlay.modeless: Rectangle {
color: "#00000000"
}
//Splash loader
Loader{
id: splash
anchors.fill: parent
source: "qrc:/Splashscreen.qml"
}
}
// Timer that will start the loading heavyObjects
Timer {
id: timer
interval: 2000
repeat: false
running: true
onTriggered: {
loader.source = "qrc:/heavyObjects.qml"
loader.active = true
}
}
//write a loader to load main.qml
Loader {
id: loader
anchors.fill: parent
asynchronous: true
active: false
//when loader is ready, hide the splashscreen
onLoaded: {
popup.visible = false
}
visible: status == Loader.Ready
}
}
SplashScreen.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
Item {
Rectangle {
id: splashRect
anchors.fill: parent
color: "white"
border.width: 0
border.color: "black"
AnimatedImage {
id: splash
source: "qrc:/images/Rotating_earth_(large).gif"
anchors.fill: parent
}
}
}
heavyObject.qml
import QtQuick
Item {
function cumsum() {
for(var j=0;j<100;j++){
var p = 0
for (var i = 0; i < 1000000; i++) {
p *= i
}
}
return ""
}
// show dummy text that this is the main windows
Text {
text: "Main Window" + String(cumsum())
anchors.centerIn: parent
}
}
Most things you do in QML are handled in the QML engine thread. If you do something heavy in that thread, it will block everything else. I haven't checked your source code, but, in terms of heavy initialization, we can break it up with Qt.callLater() or similar so that the QML engine thread can catch up on UI/UX events.
For example, in the following:
I changed cumsum from a function to a property
I introduced calcStep for do a calculation for one j iteration
I use Qt.callLater to instantiate the next iteration
I kick off the calculation during Component.onCompleted
property string cumsum
function calcStep(j) {
if (j >= 100) {
cumsum = new Date();
return;
}
for (var i = 0; i < 1000000; i++) {
p *= i
}
Qt.callLater(calcStep, j+1);
}
Component.onCompleted: calcStep(0)
}
If your initialization is more sophisticated, you may want to give Promises a try. This allows you to write asynchronous routines in a synchronous type of way, e.g.
property string cumsum
function calc() {
_asyncToGenerator(function*() {
for(var j=0;j<100;j++){
var p = 0
status = "j: " + j;
yield pass();
for (var i = 0; i < 1000000; i++) {
p *= i
}
}
cumsum = new Date();
})();
}
function pass() {
return new Promise(function (resolve, reject) {
Qt.callLater(resolve);
} );
}
Component.onCompleted: calc()
In the above, the cumsum calculation has been using a derivative of the async/await pattern. For this, to work I make use of _asyncToGenerator provided by a transpiler on babeljs.io. This is required since the QML/JS does not support async/await pattern until Qt6.6.
The pass() function operates similarly to Python pass but has my implementation of Qt.callLater wrapped in a Promise. Invoking it with yield pass(); does nothing but allows your function to momentarily release control so that the UI/UX events can catch up.
import QtQuick
import QtQuick.Controls
Page {
property string cumsum
property string status
// show dummy text that this is the main windows
Text {
text: "Main Window: " + cumsum
anchors.centerIn: parent
}
Text {
text: status
anchors.horizontalCenter: parent.horizontalCenter
y: parent.height * 3 / 4
}
function calc() {
_asyncToGenerator(function*() {
for(var j=0;j<100;j++){
var p = 0
status = "j: " + j;
yield pass();
for (var i = 0; i < 1000000; i++) {
p *= i
}
}
cumsum = new Date();
})();
}
function pass() {
return new Promise(function (resolve, reject) {
Qt.callLater(resolve);
} );
}
function _asyncToGenerator(fn) {
return function() {
var self = this,
args = arguments
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args)
function _next(value) {
_asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value)
}
function _throw(err) {
_asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err)
}
_next(undefined)
})
}
}
function _asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg)
var value = info.value
} catch (error) {
reject(error)
return
}
if (info.done) {
resolve(value)
} else {
Promise.resolve(value).then(_next, _throw)
}
}
Component.onCompleted: calc()
}
You can Try it Online!
If you are interested in some of the work I've done with async and QML Promises refer to the following GitHub projects:
https://github.com/stephenquan/qt5-qml-promises
https://github.com/stephenquan/qt5-qml-promises-demo

Error importing "Esri.ArcGISRuntime" to Qt Creator

After running the code an error came:
QQmlApplicationEngine failed to load component
qrc:/main.qml:19:1: module "Esri.ArcGISRuntime" is not installed
I am using Qt Creator 4.11.1 Qt 5.14.1
I am using Ubuntu 20.04
I have already added the path to the LD_LIBRARY_PATH as stated here: https://developers.arcgis.com/qt/install-and-set-up/
I have restarted the Qt Creator and my system but still not working.
Any suggestions?
The code is:
main.qml
import QtQuick 2.6
import QtQuick.Controls 2.2
import Esri.ArcGISRuntime 100.14 //error here
Rectangle {
id: rootRectangle
clip: true
width: 800
height: 600
readonly property int initialZoomScale: 8000
property bool trackingEnabled: false
property Point lastPosition: null
// add a mapView component
MapView {
anchors.fill: parent
Map {
Basemap {
initStyle: Enums.BasemapStyleArcGISDarkGray
}
}
// set initial viewpoint near UCLA, Los Angeles
ViewpointCenter {
Point {
x: -13185535.98
y: 4037766.28
}
targetScale: initialZoomScale
}
Button {
id: button
text: trackingEnabled ? "Stop tracking" : "Start tracking"
anchors.horizontalCenter: parent.horizontalCenter
width: 200
onClicked: trackingEnabled =! trackingEnabled
}
SimulationParameters {
id: simulationParameters
velocity: 30
}
locationDisplay {
dataSource: SimulatedLocationDataSource {
id: simulatedLocationDataSource
Component.onCompleted: {
setLocationsWithPolylineAndParameters(polyline, simulationParameters);
simulatedLocationDataSource.start();
}
}
initialZoomScale: initialZoomScale
}
// if tracking is enabled then show location history
locationDisplay.onLocationChanged: {
if (!trackingEnabled)
return;
// clear old route
locationHistoryLineOverlay.graphics.clear();
if (lastPosition !== null) {
polylineBuilder.addPoint(lastPosition);
locationHistoryOverlay.graphics.append(ArcGISRuntimeEnvironment.createObject("Graphic", {geometry: lastPosition}));
}
// update last position
lastPosition = locationDisplay.location.position;
// update the polyline
locationHistoryLineOverlay.graphics.append(ArcGISRuntimeEnvironment.createObject("Graphic", {geometry: polylineBuilder.geometry}));
}
Component.onCompleted: {
// Set the focus on MapView to initially enable keyboard navigation
forceActiveFocus();
locationDisplay.autoPanMode = Enums.LocationDisplayAutoPanModeRecenter;
}
Polyline {
id: polyline
json: {"paths":[[[-13185646.046666779,4037971.5966668758],[-13185586.780000051,4037827.6633333955],
[-13185514.813333312,4037709.1299999417],[-13185569.846666701,4037522.8633330846],
[-13185591.01333339,4037378.9299996048],[-13185629.113333428,4037283.6799995075],
[-13185770.93000024,4037425.4966663187],[-13185821.730000293,4037546.146666442],
[-13185880.996667018,4037704.8966666036],[-13185948.730000421,4037874.2300001099],
[-13185974.130000448,4037946.1966668498],[-13186120.180000596,4037958.896666863],
[-13186264.113334076,4037984.296666889],[-13186336.080000836,4038001.2300002342],
[-13186314.91333415,4037757.8133333195],[-13186272.580000773,4037560.9633331187],
[-13186187.913334005,4037463.59666635],[-13186431.33000092,4037404.3299996229],
[-13186676.863334503,4037290.0299995062],[-13187625.130002158,4038589.6633341513],
[-13187333.030001862,4038756.8800009824],[-13187091.730001617,4038617.1800008402],
[-13186791.163334643,4038805.5633343654],[-13186721.313334571,4038801.3300010278],
[-13186833.49666802,4038195.9633337436],[-13186977.677439401,4037699.8176972247],
[-13186784.921301765,4037820.4541915278],[-13186749.517113185,4038150.8932846226],
[-13186649.860878762,4038288.5762400767],[-13186556.760975549,4038323.9804286221],
[-13186472.839936033,4038481.3323777127],[-13186373.183701571,4038489.1999751539],
[-13186344.335844241,4038242.6819215398],[-13186126.665647998,4038308.245233661],
[-13185814.584282301,4038358.0733508728],[-13185651.987268206,4038116.8003622484],
[-13185203.534213299,4038048.6145176427],[-13184576.748949422,4038150.8932845518],
[-13184251.55492135,4037833.5668537691],[-13184146.653621957,4037524.1080205571],
[-13183949.963685593,4037621.1417224966],[-13183687.71043711,4037781.1162040718],
[-13183480.530370807,4037875.5273735262],[-13182307.629999243,4037859.7460188437],
[-13181376.039484169,4037820.9297473822],[-13180716.162869323,4038364.3575478429],
[-13180182.439136729,4038810.7446696493],[-13178474.523192419,4040237.2426458625],
[-13178321.134040033,4039740.6894803117],[-13177958.020228144,4039140.1550991111],
[-13177073.512224896,4037459.5898928214],[-13177757.842101147,4037589.9384406791],
[-13178386.308314031,4037799.427178307],[-13180095.012208173,4037811.6550856642],
[-13180126.165447287,4036845.9046731163],[-13179806.844746364,4036324.0879179495],
[-13180928.361354485,4035887.9425703473],[-13181598.155995468,4035428.432293402],
[-13182984.47513606,4034447.105261297],[-13182229.264383668,4033222.8051626245],
[-13182058.735615831,4033339.8690072047],[-13181939.035180708,4033691.2477038498],
[-13182116.65518121,4033861.1450956347],[-13181792.305615077,4034085.1007484416],
[-13182027.845180977,4034467.3698799671],[-13181877.254310986,4034644.9898804692],
[-13181630.130832028,4034517.5668366305],[-13181386.868657427,4034424.8955320208],
[-13181228.555178719,4034652.7124891868],[-13181379.14604871,4034942.3103160923],
[-13181267.168222306,4035189.4337950516],[-13181074.103004368,4035015.6750989081],
[-13180807.673003616,4034934.5877073747],[-13180618.469090037,4034814.8872722536],
[-13180599.162568243,4035374.7764042714],[-13181047.073873857,4035494.476839392],
[-13181317.365178969,4035413.3894478586],[-13180765.198655669,4035143.0981427468],
[-13180328.871263131,4034892.1133594285],[-13180270.951697765,4035258.9372735149],
[-13180325.009958787,4035718.4324922049],[-13180707.279090302,4035695.2646660525],
[-13181413.897788007,4035536.9511873648],[-13181618.54691902,4035807.2424924765],
[-13181884.976919774,4036065.949884512],[-13182159.129529245,4035861.3007534989],
[-13182174.57474668,4035668.2355355616],[-13182417.83692128,4035664.374231203],
[-13182784.660835361,4035409.5281435261],[-13182997.032575091,4035255.0759691764],
[-13182618.624747934,4034679.7416197238]]],
"spatialReference":{"latestWkid":3857,"wkid":102100}}
}
GraphicsOverlay {
id: locationHistoryLineOverlay
SimpleRenderer {
SimpleLineSymbol {
color: "lime"
style: Enums.SimpleLineSymbolStyleSolid
width: 2
}
}
}
GraphicsOverlay {
id: locationHistoryOverlay
SimpleRenderer {
SimpleMarkerSymbol {
color: "red"
style: Enums.SimpleMarkerSymbolStyleCircle
size: 3
}
}
}
}
PolylineBuilder {
id: polylineBuilder
spatialReference: SpatialReference { wkid: 3857 }
}
}
I will summarise the issues discussed in the comment thread to bring to an end.
Use Qt 5.15 these days and preferably always the latest bug fix release. Which is currently 5.15.5 for open-source, and not commercial, customers at the time of writing this. Even better to switch to 6.x when possible.
Setting the QML_IMPORT_TRACE environment variable can help debugging these issues.
When using qmake, they seem to suggest including their pri file to your qmake pro file.
Something like a export QML2_IMPORT_PATH=..:$QML2_IMPORT_PATH can also help localising these issues as a quick experiment.

Qt.createComponent url of the library components

Below is a function from TimelinePresenter.qml which is a custom component I created.
function createMenu() {
var menuComp = Qt.createComponent("Menu.qml");
if( menuComp.status != Component.Ready )
{
if( menuComp.status == Component.Error )
console.debug("Error: " + menuComp.errorString());
return;
}
}
It gives the error:
Error: qrc:/qml/timeline/Menu.qml:-1 No such file or directory
TimelinePresenter.qml is a resource file specified in the .qrc file and its path is qml/timeline as shown in error message so qml engine is trying to find the Menu.qml there expectedly. How can I specify the path to create qt's Menu component?
Edit:
my resources.qrc file
<RCC>
<qresource prefix="/">
<file>qml/main_window.qml</file>
<file>qml/timeline/TimelineViewItem.qml</file>
<file>qml/timeline/HorizontalLine.qml</file>
<file>qml/timeline/TimelineView.qml</file>
<file>qml/timeline/VerticalLine.qml</file>
<file>qml/timeline/timeline-item/timeline_item.h</file>
<file>qml/timeline/TimelinePresenter.qml</file>
<file>qml/timeline/timeline-item/analog_timeline_item.h</file>
<file>qml/timeline/timeline-item/digital_timeline_item.h</file>
<file>qml/timeline/timeline_presenter_backend.h</file>
<file>qml/ControllableListPresenter.qml</file>
<file>qml/controllable_list_backend.h</file>
<file>qml/controllable-popup/AddControlUnitPopup.qml</file>
<file>qml/styled/CenteredPopup.qml</file>
<file>qml/styled/StyledTextField.qml</file>
</qresource>
</RCC>
You are confusing the creation of a component with the creation of an object that belongs to a component.
The Menu component already exists and is provided by Qt, what you must do is create the object using the Qt.createQmlObject() method.
Example:
var menuObj = Qt.createQmlObject('import QtQuick.Controls 2.0 ; Menu {
MenuItem { text: "Cut" }
MenuItem { text: "Copy" }
MenuItem { text: "Paste" } }', parentItem, "dynamicSnippet1");
Complete Example:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: parentItem
Component.onCompleted: {
var menu = Qt.createQmlObject('import QtQuick.Controls 2.0 ; Menu {
MenuItem { text: "Cut" }
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}', parentItem,"dynamicSnippet1");
// test: open menu
menu.open()
}
}
In the case you have described in your comments, I would suggest to only create one Menu and only popup() it at the place where you have clicked, setting it in a specific context.
I prepared a small example to illustrate how the Menu could be used:
import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 2.3 // Necessary for the "Action" I used. Create the Menu otherwise if you are bound to older versions.
import QtQml 2.0
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
Repeater {
model: ListModel {
ListElement { color: 'black'; x: 400; y: 50 }
ListElement { color: 'black'; x: 100; y: 190 }
ListElement { color: 'black'; x: 70; y: 80 }
ListElement { color: 'black'; x: 30; y: 0 }
ListElement { color: 'black'; x: 340; y: 500 }
ListElement { color: 'black'; x: 210; y: 10 }
}
delegate: MouseArea {
x: model.x
y: model.y
width: 50
height: 50
property QtObject modelItem: model
onClicked: menu.openMenu(x + mouse.x, y + mouse.y, modelItem)
Rectangle {
color: model.color
anchors.fill: parent
}
}
}
Menu {
id: menu
Action { text: "green" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "blue" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "pink" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "yellow" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "orchid" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "orange" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "teal" ; onTriggered: { menu.currentContext.color = text } }
Action { text: "steelblue"; onTriggered: { menu.currentContext.color = text } }
property QtObject currentContext
function openMenu(x, y, context) {
currentContext = context
popup(x, y)
}
}
}
Though I think this answer might solve your problem, I know that it is not really the answer to the question you stated initially.
For the Component-part: I think you misunderstood what a Component is - it is not an Item. It is a prestage in the creation of QtObjects and more something like a prototype or configured factory.
So your function - if it would work - would end at the creation of a invisible thing, from which you could create objects, by calling createObject().
Creating Components is the right thing to do, if you want to create an object at a later time and you might want to create similar objects multiple times, either by JavaScript or by other QML-types that expect Components as some input (e.g. delegates).
To create Components you have multiple possibilities, e.g.:
Qt.createComponent(url)
Component { SomeItem {} }
The first expects you to know the url, which in your case, you do not. To circumvent that, the easiest solution is, to create a new File, like MyMenu.qml
that only contains the Menu {} - then you can create a Component from this.
The second does not expects you to know the url, but it is not dynamically created.
Component {
id: myCmp
Menu {
}
}
onSomeSignal: myCmp.createObject({ prop1: val1 }, this)
Here the Component is automatically created when the object in the file is instantiated. This makes that (one time) initially a bit slower, since more code has to be processed, but you don't have to do it later.
Creating objects like eyllanesc shows with Qt.createQmlObject("Write a new QML-File here") might be also used to create a Component if the top-level element is a Component. If you don't have a Component as top-level, it will also first create a component that is once used to create a QtObject and then is discarded. It is the slowest but most flexible way to dynamically create objects.

how to implement search function in Qt Quick folderListmodel ??

I want implement search functioning to my music player totally written in Qml
. In my case i initiated a qml Filedialog to get folder from filesystem and then i used folderListModel to list them through ListView .
I want search through the list any clue how can i achieve this ????
Please don't suggest to use c++ . and also not suggest me to use nameFilters :["*."] in foldelistmodel cause it wont work it only filter according to extension of file not the file name
Actually nameFilters does allow to filter by filename. Using a kind of hack, it is even possible to make it case insensitive.
Here is an ugly but working example:
import QtQuick 2.3
import QtQuick.Controls 1.2
import Qt.labs.folderlistmodel 2.1
Item {
width: 300
height: 300
FolderListModel
{
id: folderListModel
}
function updateFilter()
{
var text = filterField.text
var filter = "*"
for(var i = 0; i<text.length; i++)
if(!caseSensitiveCheckbox.checked)
filter+= "[%1%2]".arg(text[i].toUpperCase()).arg(text[i].toLowerCase())
else
filter+= text[i]
filter+="*"
print(filter)
folderListModel.nameFilters = [filter]
}
Row
{
spacing: 5
Text {text:"Filter"}
TextField
{
id: filterField
onTextChanged: updateFilter()
}
Text {text:"Case Sensitive"}
CheckBox
{
id: caseSensitiveCheckbox
checked: false
onCheckedChanged:updateFilter()
}
}
ListView
{
anchors.fill: parent
anchors.topMargin: 30
model:folderListModel
delegate: Text{text: model.fileName}
}
}
Use DelegateModel :
with DelegateModelGroup to sort and filter delegate items.
Assume that you have a function to filter files using filename,
function willBeShownOnView(filename){ /* ... */ }
You can extend this function by passing more roles (fileSize, fileIsDir, ...) or filter string entered by user if you need, and implement the filtering logic within this function.
Next, create a DelegateModel with a filterGroup:
DelegateModel {
id: delegateModel
model: FolderListModel{id: folderModel}
groups: [
DelegateModelGroup {
name: "filterGroup"; includeByDefault: true
}
]
filterOnGroup: "filterGroup"
delegate: MyFileDisplayComponent{/* ... */}
function applyFilter(){ /* see below */}
}
As includeByDefault: true, all items in folderModel are included in the filterGroup. And when we applyFilter, some items should be removed from this group. For example,
function applyFilter(){
var numberOfFiles = folderModel.count;
for (var i = 0; i < numberOfFiles; i++){
var fileName = folderModel.get(i, "fileName");
if (willBeShownOnView(fileName)){items.addGroups(i, 1, "filterGroup");}
else {items.removeGroups(i, 1, "filterGroup");}
}
}
After applyFilter is called, only files that passes willBeShownOnView is added to the filterGroup. And the property filterOnGroup: "filterGroup" says the delegate model contains only items within the filterGroup. Therefore, we can use a simple ListView to display the result:
ListView {
model: delegateModel
//...
}

How can I switch the focus for the pop-up window?

I encounter a problem which is that the pop-up window cannot get the focus when it is shown. I tried to use the activefocus function in main window, but it doesn't work. It is supposed that if I press the enter key, the pop-window will be closed. How can I get the focus for the pop-up window? Thanks.
...
GridView {
id:grid_main
anchors.fill: parent
focus: true
currentIndex: 0
model: FileModel{
id: myModel
folder: "c:\\folder"
nameFilters: ["*.mp4","*.jpg"]
}
highlight: Rectangle { width: 80; height: 80; color: "lightsteelblue" }
delegate: Item {
width: 100; height: 100
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
text: fileName
}
MouseArea {
anchors.fill: parent
onClicked: {
parent.GridView.view.currentIndex = index
}
}
}
Keys.onPressed: { //pop up window
if (event.key == 16777220) {//enter
subWindow.show();
subWindow.forceActiveFocus();
event.accepted = true;
grid_main.focus = false;
}
}
}
Window {
id: subWindow
Keys.onPressed: {
if (event.key == 16777220) {//press enter
subWindow.close();
}
}
}
...
Let's start with some basics:
Keys.onPressed: { //pop up window
if (event.key == 16777220) {//enter
subWindow.show()
...
event.accepted = true
}
}
Not to mention how error-prone it is, just for the sake of readability, please don't hard-code enum values like 16777220. Qt provides Qt.Key_Return and Qt.Key_Enter (typically located on the keypad) and more conveniently, Keys.returnPressed and Keys.enterPressed signal handlers. These convenience handlers even automatically set event.accepted = true, so you can replace the signal handler with a lot simpler version:
Keys.onReturnPressed: {
subWindow.show()
...
}
Now, the next thing is to find the correct methods to call. First of all, the QML Window type does not have such method as forceActiveFocus(). If you pay some attention to the application output, you should see:
TypeError: Property 'forceActiveFocus' of object QQuickWindowQmlImpl(0x1a6253d9c50) is not a function
The documentation contains a list of available methods: Window QML type. You might want to try a combination of show() and requestActivate().
Keys.onReturnPressed: {
subWindow.show()
subWindow.requestActivate()
}
Then, you want to handle keys in the sub-window. Currently, you're trying to attach QML Keys to the Window. Again, if you pay attention to the application output, you should see:
Could not attach Keys property to: QQuickWindowQmlImpl(0x1ddb75d7fe0) is not an Item
Maybe it's just the simplified test-case, but you need to get these things right when you give a testcase, to avoid people focusing on wrong errors. Anyway, what you want to do is to create an item, request focus, and handle keys on it:
Window {
id: subWindow
Item {
focus: true
Keys.onReturnPressed: subWindow.close()
}
}
Finally, to put the pieces together, a working minimal testcase would look something like:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: window
width: 300
height: 300
visible: true
GridView {
focus: true
anchors.fill: parent
// ...
Keys.onReturnPressed: {
subWindow.show()
subWindow.requestActivate()
}
}
Window {
id: subWindow
Item {
focus: true
anchors.fill: parent
Keys.onReturnPressed: subWindow.close()
}
}
}
PS. Key events rely on focus being in where you expect it to be. This may not always be true, if the user tab-navigates focus elsewhere, for example. Consider using the Shortcut QML type for a more reliable way to close the popup.

Resources