how to get the full URL from a QML WebView - qt

When clicking on a link inside of a QT Quick WebView (something like "http://example.com/page?abc=def&bca=fde"), the url property doesn't contain the query string (giving only "http://example.com/page").
I tried console.log(webView.url) (webView being the ID of my WebView component) expecting it to be "http://example.com/page?abc=def&bca=fde", the result was "http://example.com/page" instead
Is there a way to get the query part?

I don't know exactly what you are doing, but it works correctly in my example. I'm using Qt 6.4.0.
Steps to reproduce:
Start example application
Type in qt in the google search field
Hit enter
Click on the image tab
View link with query part
The output will look as follows
qml: URL https://www.google.com/search?q=qt&source=lnms&tbm=isch&sa=X&ved=2ahUKEwiLxPKM4NX8AhVzS_EDHXYmAkwQ_AUoAXoECAEQAw&biw=800&bih=600
qml: LOAD https://www.google.com/search?q=qt&source=lnms&tbm=isch&sa=X&ved=2ahUKEwiLxPKM4NX8AhVzS_EDHXYmAkwQ_AUoAXoECAEQAw&biw=800&bih=600
Here is the code
import QtQuick
import QtWebView
Window {
id: root
width: 800
height: 600
visible: true
title: qsTr("Hello WebView")
WebView {
id: webView
anchors.fill: parent
url: "https://www.google.com"
onUrlChanged: console.log("URL", webView.url)
onLoadingChanged: function(loadRequest) {
console.log("LOAD", loadRequest.url)
if (loadRequest.errorString)
console.error(loadRequest.errorString);
}
}
}

Related

Popup in qml : (closePolicy: Popup.NoAutoClose)

When ever i am using closePolicy: Popup.NoAutoClose,
This popup is opened all the time and not getting closed (which is valid). When i am switching to some other screen, popup is opened and visible in other screens also.
How to avoid this kind of behaviour?
Note: I want popup to be visible specific to that particular screen where it is opened and not on other screens.
You can use Binding to control the popup's visibility based on the name of the screen it was opened in:
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow {
id: window
width: 400
height: 400
visible: true
Popup {
id: popup
width: 200
height: 200
visible: true
closePolicy: Popup.NoAutoClose
property string originalScreenName
Component.onCompleted: originalScreenName = ApplicationWindow.window.screen.name
Binding {
target: popup
property: "visible"
value: popup.ApplicationWindow.window.screen.name === popup.originalScreenName
}
}
}
I don't know if the name property can change during the lifetime of the application (e.g. due to a user renaming it), but so far it's the only way I've found of uniquely identifying a screen, as the other properties like serialNumber are not set for me, and QTBUG-85934 prevents comparing screen objects.

How to inject data into QT item shown with loader

In my application I have a global system that handles navigation between "screens". In QML I can simply call something like:
appNavigation.show("MyScreen.qml", NavigationType.FADE)
this calls a C++ part of the code which handles the current stack of screens and uses signals to report back to QML to do the actual animation. At the end in QML some Loader will load the input qml ("MyScreen.qml" in this case) and show it as defined.
My issue here is how to inject data into newly loaded screen. Essentially I would like to do something like the following:
function showMyScreen() {
MyScreen screen = appNavigation.show("MyScreen.qml", NavigationType.FADE)
screen.someData = "some data here"
}
but is this possible? Could I somehow return the screen that is loaded by the loader?
I am guessing not so I would satisfy with sending the data with the navigation itself like:
function showMyScreen() {
MyScreen screen = appNavigation.show("MyScreen.qml", NavigationType.FADE, "some data here")
}
I could forward the data to the point where I set source to the loader but still what then? How or where would that specific screen that is going to be loaded get the data. To reduce is this is what I get:
function setNewItemWithData(newItem, data) {
loader.source = newItem
loader.concreteScreen.data = data // Not really doable
}
again I assume this is not doable and I need to forward the data down to loader and use onLoaded event. So what I would do is something like:
onLoaded: {
myLoadedScreen.data = data
}
I assume something like this is possible but how? What am I missing here, how do I get myLoadedScreen and how to access its properties?
What I am currently doing now is dumping the data in C++ part and then collecting it in the loaded QML. So like the following:
appNavigation.injectedData = "some data here"
and then in the newly loaded item:
property data = appNavigation.injectedData
It works but this seems like extremely poor coding. Any of the alternatives would be helpful.
Thank you for your patience.
Since the request for MCVE was made:
This is a general problem and I expect it to have multiple solutions. I would be looking forward to any of them. However the minimal example to produce this is creating a new project and adding a loader with another qml to which some property should be changed:
main:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Loader {
anchors.fill: parent; anchors.margins: 20
source: "MyScreen.qml"
// TODO: make screen green (loadedScreen.color = "green")
}
}
MyScreen:
import QtQuick 2.0
Rectangle {
color: "red"
}
Current result is seeing a red rectangle and desired result is to see a green one. The point being that the main screen needs to tell what color the loaded screen needs to use.
You have to use the item property of the Loader to get the object loaded:
Loader {
id: loader
anchors.fill: parent; anchors.margins: 20
source: "MyScreen.qml"
onLoaded: loader.item.color = "green"
}
To do that, you might as well use Component (If you use it when reacting to an event)
Component {
id: myScreenComponent
MyScreen {
anchors.fill: parent
}
}
function showMyScreen() {
myScreenComponent.createObject(this, {"color: "green"});
}
Alternatively, given your first code, I would recommend you to use StackView.
The push method seems to be similar to your appNavigation.show one.
You can give it an url, some properties, and a transition type (that you can customize).

Spawn QtQuick UI file from a normal QML Window class

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.

QtQuick - button onClick event

Background story
So I recently decided that I should try out Qt. I started making a QtQuick Apllication. In my designer view I have one button and a mouse area.
What I want to do:
When I click the button, I want to display a message box with some text (like "Hello World").
My Question
How can I do that ?
Additional info
I tried googling it, i tried following this answer. But still nothing.
I know how to program in .Net (C# and VB), i have some knowage in C/C++, but Qt seems to hard for me
How about this:
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Dialogs 1.1
Rectangle {
width: 360
height: 360
MessageDialog {
id: msg
title: "Title"
text: "Button pressed"
onAccepted: visible = false
}
Button {
text: "press me"
onClicked: msg.visible = true
}
}
And if you prefer to have the dialog dynamically instantiated with arbitrary properties rather than have it "hardcoded", follow the first snippet from this answer. You can also set properties in createQmlObject() and instead of hiding the dialog just use destroy() to delete it.
You have to use signals and slots in order to trigger an event. You could use a QMessageBox that pops up to display Hello world.

Why QML MediaPlayer/VideoOutput doesn't work for me?

I'm trying to play test video with qml by this code:
import QtQuick 2.2
import QtMultimedia 5.0
Item {
width: 300
height: 300
MediaPlayer {
id: player
source: "C:\\Downloads\\video.mp4"
}
VideoOutput {
id: video
anchors.fill: parent
source: player
}
MouseArea {
anchors.fill: parent
onPressed: player.play()
}
}
But, when I click on view, nothing happens. And if I change onPressed event to something else action (not with the player), it works fine, then it's not a MouseArea problem.
Where did I wrong?
Thank you.
The file path seems to be wrong. Since baclslashes need to be escaped in string litterals, the actual path remaining is:
c:\Downloads\video.mp4
That's a path, but not an URL. The correct URL is (see File URIs in Windows):
file:///C:/Downloads/video.mp4
On your code source:
C:\\Downloads\\video.mp4
should be source:
C://Downloads//video.mp4

Resources