How to display embedded html in Qt WebView - qt
I am trying to get the Qt WebView to display an html file that is embedded as a Qt resource, but I can't seem to get it to work. I created a new Qt Quick application and added a simple qml file:
import QtQuick 2.0
import QtWebKit 3.0
Rectangle {
id: content
width: 800
height: 600
color: "black"
WebView {
id: webView
anchors.fill: parent
url: "qrc:/res/test.html"
}
}
I then created (using the Designer) a resource file that looks like this:
<RCC>
<qresource prefix="/res">
<file>test.html</file>
</qresource>
</RCC>
and created a simple test.html file (in the same directory as the .qrc file):
<html>
<head><title>Hello</title></head>
<body>
<h1>Hello World!</h1>
</body>
</html>
The result is just a blank white window. If I use a regular url (http://www.stackoverflow.com) in the qml file as the url it works - the page is displayed. If I use the name of an embedded image (qrc:/qt-project.org/mac/cursors/images/pluscursor.png) that image is displayed.
It looks to me as if the html file is indeed added (it is at least listed when I enumerate the embedded resources), but my understanding of the Qt resource system is limited, so I may very well have misunderstood something fundamental.
Can anyone tell me what I am doing wrong?
Update: I have verified that the behavior is the same if I attempt to tell the web view to load the url from C++ as well. I have also verified that the resource is indeed embedded - I can open and read the resource using a QResource. Also, this does not appear to be specific to Qt5: http://qt-project.org/forums/viewthread/18181 (someone having a similar problem with Qt 4.8).
First , make sure that resource file is compiled correctly on compile folder (a .RCC file or a qrc_<Resource name>.cpp)
Second, make sure your file path is correct (in my case qrc:/images/resource/html/test.html). You can open QRC file and right-click on html file and then click on Copy Resource Path to Clipboard.
Third, Note that some urls needs more time for loading completely.
Finally, I test this scenario and it works very well (Using Qt 5.1.0)
Good luck - S.M.Mousavi
I don't thing it's possible opening resource from qrc directly in WebView (I've tried all url variants). What I'm doing now is copying the file to the local temp directory and then opening.
QString helpHTMLFile = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
helpHTMLFile.append(QDir::separator());
helpHTMLFile.append("software_manual.html");
QFile(helpHTMLFile).remove();
QFile(":/software_manual.html").copy(helpHTMLFile);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("pathToFile", "file:///"+helpHTMLFile);
Then QML looks like:
WebView {
anchors.fill: parent
url: pathToFile
}
Ok, here's how I ended up solving this. I ended up using a plain widget instead of a qml based interface.
I then had to read the first html page out from the resources manually and provide the base url. After that, subsequent pages and resources that are embedded as resources load fine.
Here's the code in question:
QResource res(":/html/index.html");
ui->webView->setHtml(reinterpret_cast<const char *>(res.data()), QUrl("qrc:/html/"));
where webView is a QWebView. My .qrc file looks like this:
<RCC>
<qresource prefix="/">
<file>html/index.html</file>
</qresource>
</RCC>
This works in Qt 5.5.0.
The quickest way to load a resource file is using XMLHttpRequest and loadHtml().
This works in Qt 5.10.1 for mobile platforms.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtWebView 1.1
Page {
anchors.fill: parent
WebView {
id: webView
anchors.fill: parent
Component.onCompleted: {
var resource = 'qrc:/path/to/your/resource.html';
var xhr = new XMLHttpRequest;
xhr.open('GET', resource);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
var response = xhr.responseText;
webView.loadHtml(response);
}
};
xhr.send();
}
}
}
why not just use
url: "res/test.html"
instead of
url: "qrc:/res/test.html"
?
Then you would not need to use any resource files
Embedded resources URLs loading support by web engine is available in latest Qt at least for WebEngineView in QML. I was not able to find official documentation about this, but one official sample loads page from resources:
WebEngineView {
url: "qrc:/index.html"
...
}
It works for me with Qt 5.8.0 as well.
You can put below line just after QApplication a(argc, argv);
QtWebView::initialize();
Just use Path-To-File & If you saved it in project directory, just set name of file
url: "/res/test.html"
& if file is in project directory
url: "test.html"
Related
Qt Creator autocomplete values for a global qml object in a file which is loaded by Stackloader?
So in QML, I can declare a stackview like this: ApplicationWindow { Item{ id: globalObject specialProperty: "xyz" } StackView{ id: sv } } Then I have a button which loads a "Page1.qml" file into the StackView. When the program runs, I can access the globalObject from code in Page1.qml but qtCreator's autocomplete is oblivious to this connection. It is not very quick to go back and forth between Page1.qml and main.qml to find the name of special property especially when there are many objects that have to be shared between multiple pages. In general, what I want to know, is there a way to statically link a response to a dynamically loaded object or leave a hint for the IDE that the following objects in this file are available to this other file?
How to change WebView settings from QML
I'm using a simple WebView in my QML file. WebView { anchors.fill: parent url: "file:///android_asset/example.html" } The problem is, that I'm getting an error about access-control-allow-origin is null. I found a fix for this here, which is using WebView settings property. It seems to be accessible from c++, but I haven't found any way of using this property from qml. So how can I use WebView settings from QML to get rid of the error? I'm using Qt 5.10.
Use Qt's resource system, add the file to it, and load the file via url: "qrc:///android_assets/example.html"
Qt Quick Controls 2 hangs when overwriting Button.qml
I'm trying to implement my own style and for this I want to override the built-in objects. Here's what I'm doing: // main.cpp QQuickStyle::setStyle("mystyle"); and // mystyle/Button.qml import QtQuick 2.5 import QtQuick.Controls 2.1 as Controls Controls.Button { background: Rectangle { color: "green" } } and // qml.qrc <RCC> <qresource prefix="/"> <file>main.qml</file> <file>mystyle/CheckBox.qml</file> </qresource> </RCC> According to the docs I believe this should work automagically using file selectors. However, my app hangs on startup. My guess is that I fall into a recursive import. How do I do this correctly?
The Qt Quick Controls 2 styling system is based on QML type registration. When you run your app with mystyle, the type known as QtQuick.Controls.Button IS mystyle/Button.qml. Therefore mystyle/Button.qml cannot inherit QtQuick.Controls.Button. It cannot inherit itself. This is basically the same as writing the following C++: // button.h #include "button.h" class Button : public Button {}; A bit radicalized, but easy to understand analogy. :) What you can do is to have (My)Button.qml somewhere, let it inherit QtQuick.Controls.Button, and don't register it as a Qt Quick Controls 2 but simply import the folder. This is what we call as "Customizing Qt Quick Controls 2".
The style must be configured before loading QML that imports Qt Quick Controls.It is not possible to change the style after the QML types have been registered. setStyle() Apply the existing style in your custom style's qml files. Note: It is recommended to use QQmlApplicationEngine, which internally creates a QQmlFileSelector instance. This is all that is needed to take QML file selectors into use. See: Creating Custom Styles
declare global property in QML for other QML files
I want to declare a global property in a config file and use it in other files. for example declare mainbg in: Style.qml: property color mainbg: 'red' and use it in other QML files (like view.qml and main.qml). How can I do this work?
Use a QML Singleton. Please reference "Approach 2" on this page -- The ugly QTBUG-34418 comments are mine. These are the pieces you need: Style.qml pragma Singleton import QtQuick 2.0 QtObject { property color mainbg: 'red' } qmldir This file must be in the same folder as the singleton .qml file (Style.qml in our example) or you must give a relative path to it. qmldir may also need to be included by the .qrc resource file. More information about qmldir files can be found here. # qmldir singleton Style Style.qml How to Reference import QtQuick 2.0 import "." // this is needed when referencing singleton object from same folder Rectangle { color: Style.mainbg // <- there it is!!! width: 240; height 160 } This approach is available since Qt5.0. You need a folder import statement even if referencing the QML singleton in the same folder. If is the same folder, use: import "." This is the bug that I documented on the qt-project page (see QTBUG-34418, singletons require explicit import to load qmldir file).
Basically, if you don't need property binding (if you value is a constant and will not need to be notifiable on change) you can define it in a Javascript shared library, like this : // MyConstants.js .pragma library var mainbg = "red"; And use it in QML like this : import "MyConstants.js" as Constants Rectangle { color: Constants.mainbg; } But the bad side of this are : - no strong typing (JS doesn't really know about types) so you could put anything even if it is not a color. - and if you change mainbg, the Item using it won't be notified about the change and will keep the old value So if you need type checking and binding/change notify, simply declare your property as a member of the root object in you main.qml, and it will be accessible from everywhere in the QML application, because the property will in fact be directly registered into the Qml Context object, which is global by definition. Hope it helps.
You can create a js file and import it to all of the files that have to use this property. js file: //Note: you only need '.pragma library' if you are planning to //change this variable from multiple qml files .pragma library var globalVariable = 20; qml file: import "test.js" as Global Rectangle { id: main width: 300; height: 400 Component.onCompleted: { console.log( Global.globalVariable) //you can also change it Global.globalVariable = 5 } }
Adding some contribute to #pixelgrease answer, I found another technique that doesn't require the path relative import ".", workarounding the bug QTBUG-34418. This is useful especially if one has qmldir and singleton class in a different place than the qml file where the singleton is used. The technique requires defining a proper module inside the tree structure: the module is then resolved by adding the parent path of the module to the QML engine with QmlEngine::addImportPath(moduleParentPath). For example: qml/ ├── <ModuleName>/ │ ├── <ClassName>.qml │ ├── qmldir In main.cpp you have then: QQmlApplicationEngine engine; engine.addImportPath("qrc:/qml"); // Can be any directory engine.load("qrc:/qml/main.qml"); If you use resources, qml.qrc: <RCC> <qresource prefix="/"> (...) <file>qml/main.qml</file> <file>qml/MySingletons/MySingleton.qml</file> <file>qml/MySingletons/qmldir</file> </qresource> </RCC> In qmldir: module MySingletons singleton MySingleton 1.0 MySingleton.qml In main.qml, or any other qml file in a different directory: import MySingletons 1.0 Then you use MySingleton class as usual. I attached the example MySingletonWithModule.7z to bug QTBUG-34418 for reference.
Add this property in main and you can access it in any qml,this may not be the correct way but this works. or if you want to group the property add them in a qml include that qml in main and give an id,now you can access this property using that id main.qml Item{ width:10 height:10 Model{ id:globdldata } } Model.qml Item { property color mainbg: 'red' } you can use globdldata.mainbg anywhere
You can always create a new QML object file that contains the properties that you want shared across qml files. Just import it the same way you would any QML object and you have access to properties. Now, if you want to be able to modify these properties and have the changes shared across instances things get a lot trickier and you will most likely want to resort to some sort of solution using the .pragma library js files. Unless you want to write some sort of C++ alternative.
How to get the error message from a failed url load in a Qt WebView
say I have a basic QML file which listens for the onLoadFailed signal like this: import QtQuick 1.1 import QtWebKit 1.0 WebView { onLoadFailed: { } url: "bogus_url" } In this example, I should get a 404 or a 500. What should I put in the onLoadFailed to output the error message that was returned?
I'm afraid you can't do it using a simple QML WebView. You can use a [bad] trick described in this thread on the QT forum. Otherwise you'll have to make your own QDeclarativeItem extending the WebView with all the infos you need.