how to import a QML Component resource in a QML file - qt

I have the following directory structure:
ui/
|- resources.qrc
|- qml/
|- main_window_presenter.qml
|- MyPresenter.qml
resources.qrc contents:
<RCC>
<qresource prefix="/">
<file>qml/MyPresenter.qml</file>
<file>qml/main_window_presenter.qml</file>
</qresource>
</RCC>
MyPresenter.qml contents:
import QtQuick 2.11
FocusScope {
id: root
property Item view
property QtObject model
Component.onCompleted: {
root.view.anchors.fill = root
root.view.focus = true
}
}
main_window_presenter.qml contents:
import "."
MyPresenter {
id: root
}
main.cpp contents:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(":/qml/main_window_presenter.qml");
return app.exec();
}
When I run the application I get
QQmlApplicationEngine failed to load component
file::/qml/main_window_presenter.qml:1 import "." has no qmldir and no namespace
If I delete import "." at main_window_presenter.qml I get
QQmlApplicationEngine failed to load component
file::/qml/main_window_presenter.qml:3 MyPresenter is not a type
I think I shouldn't need an import statement because they are in the same directory. I am using meson build system with this relevant part in meson.build(exe_moc_headers are defined before):
qt5_module = import('qt5')
exe_processed = qt5_module.preprocess(moc_headers : exe_moc_headers, qresources : 'ui/resources.qrc')

As #eyllanesc suggested QQuickView works instead of QQmlApplicationEngine:
#include <QGuiApplication>
#include <QQuickView>
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QQuickView* view{new QQuickView};
view->setSource(QUrl("qrc:///qml/main_window_presenter.qml"));
view->show();
return app.exec();
}
I might have figured it myself if the error message wasn't indicating that type is not found by saying "MyPresenter is not a type". This led me to believe that its a referencing issue.

Related

Import Qt function to QML file?

How do you call for example QFile::exists(path) inside a QML file in Qt 5.5?
MyFile.qml
import QtQuick 2.5
// These are some various things I've tried, with the error message they
// give related to the row where I call QFile::exists()
#include <QFile> // Expected token `{'
import QtQml 2.5 // Expected token `;'
import io.qt // Expected token `;'
import io.qt.QFile // Expected token `;'
Item {
id: root
property string imageSource
Image {
id: test
source: fileOrFallback(root.imageSource)
}
function fileOrFallback (source) {
return QFile::exists(source)
? preprocessor.getFilePath(source)
: theme.example + 'placeholder.png'
}
}
I've seen some examples on how to import your custom Qt functions, but how do you call built-in Qt functions in QML?
You cannot directly import a C ++ function, in these cases the approach is to create a QObject that exposes the method through a Q_INVOKABLE:
backend.h
#ifndef BACKEND_H
#define BACKEND_H
#include <QObject>
class Backend : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
Q_INVOKABLE bool exists(const QString &fileName);
};
#endif // BACKEND_H
backend.cpp
#include "backend.h"
#include <QFile>
bool Backend::exists(const QString &fileName){
return QFile::exists(fileName);
}
main.cpp
#include "backend.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
Backend backend;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("backend", &backend);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
*.qml
// ...
function fileOrFallback (source) {
return backend.exists(source)
? preprocessor.getFilePath(source)
: theme.example + 'placeholder.png'
}
// ...

Load image in QML WebEngineView using QQuickImageProvider

I'm injecting HTML content into a QML WebEngineView using the loadHtml method, and I'm trying to get it to load the images through a QQuickImageProvider.
Up to now, we've been successfully loading images from a Qt resource container (qrc), but this is not flexible enough.
contentimageprovider.cpp
#include "contentimageprovider.h"
#include <QDebug>
ContentImageProvider::ContentImageProvider() : QQuickImageProvider(QQuickAsyncImageProvider::Image)
{
}
QImage ContentImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
qDebug() << __FUNCTION__ << id;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtWebEngine/QtWebEngine>
#include "contentimageprovider.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QtWebEngine::initialize();
engine.addImageProvider(QLatin1String("content-images"), new ContentImageProvider);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Window 2.2
import QtWebEngine 1.4
Image {
source: "image://content-images/this-image-is-requested";
}
WebEngineView {
Component.onCompleted: {
loadHtml("<img src='qrc://images/this-image-is-displayed.png' /><img src='image://content-images/this-image-should-also-be-requested' />", "/");
}
}
Expected output
requestImage "this-image-is-requested"
requestImage "this-image-should-also-be-requested"
Actual output
requestImage "this-image-is-requested"
And the image loaded via qrc in the WebEngineView is displayed, and a broken image is shown for the other one.
Has anyone been able to get this to work?
Thanks to #Xplatforms who pointed out the initial error in assuming that the Chromium engine under the QML WebEngineView would interact with the QML Quick engine and trigger the image provider.
The solution was to implement a QWebEngineUrlSchemeHandler:
void ImageRequestHandler::requestStarted(QWebEngineUrlRequestJob *request)
{
// request->requestUrl() is a QUrl
QFile *image = new QFile(QDir::currentPath() + "/storage/content/" + request->requestUrl().path() + ".png");
// makes sure the image deletes itself when closing the file
connect(image, &QIODevice::aboutToClose, image, &QObject::deleteLater);
// close the file when the request job is done
connect(request, &QObject::destroyed, image, &QIODevice::close);
QMimeDatabase mimeDB;
QMimeType mimeType = mimeDB.mimeTypeForFile(image->fileName());
request->reply(mimeType.name().toUtf8(), image);
}
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// web engine to provide content display
QtWebEngine::initialize();
// intercept requests from the web engine to provide locally loaded content and images
ImageRequestHandler *imageRequestHandler = new ImageRequestHandler();
QQuickWebEngineProfile::defaultProfile()->installUrlSchemeHandler("image", imageRequestHandler);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}

How to use QtTest with qbs

I can't find clear example of building tests with qbs.
I tried like this
import qbs
CppApplication {
consoleApplication: true
files: [ "TestTask.h", "TestTask.cpp" ]
Depends { name: "Qt"; submodules: [ "core", "testlib" ] }
}
TestTask is a QObject subclass.
But compiler says that I missed main() function.
For compile test your need main.cpp. For example:
#include <QCoreApplication>
#include <QTest>
#include "TestTask.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTest::qExec(new TestTask, argc, argv);
return 0;
}
Your must also add main.cpp in files (qbs file).

QML import QtCharts module error

When I try to import the QtCharts module to my QML files y always get the same warning message:
"found not working imports: file: C:/.... module "QtCharts" is not
installed"
I'm using OpenSource QtCreator 4.0.3 with Qt 5.7.0.
I have the folder QtCharts in the path: C:\Qt\5.7\mingw53_32\qml
I've also included the folder path using the property in the .pro file:
QML2_IMPORT_PATH: C:\Qt\5.7\mingw53_32\qml
What am I missing?
Here is a simple test code:
// QtChartsTest.pro
TEMPLATE = app
QT += qml quick
QT += charts
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML2_IMPORT_PATH = C:\Qt\5.7\mingw53_32\qml
# Default rules for deployment.
include(deployment.pri)
// Main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
// Main.qml
import QtQuick 2.7
import QtQuick.Window 2.2
import QtCharts 2.1
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
I was stuck on a similar issue and was frustrated by Qt's documentation on the subject, so I'll put my method of solving my own issues here for posterity.
I'm not sure of the exact cause of your issue, but I can offer you a suggestion to try and troubleshoot it.
In your main.cpp add the following line.
qDebug()<<engine.importPathList();
So your main will be
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDebug>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qDebug()<<engine.importPathList();
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
This will include the complete list of include paths. If you do not see the include path listed there you can add it by adding the following line:
engine.addImportPath(directory);
where "directory" is a QString to the include directory.
My understanding is that the QML2_IMPORT_PATH variable only applies at run time, and not at compile time, which means that QtCreator does not see the path when it compiles. engine.addImportPath(directory); on the other hand adds the path prior to starting the qml engine, (and thus the first qml import statements)
I am not saying this is the best way to solve your issue, but it did help me solve my issue.
int main(int argc, char *argv[])
{
// Qt Charts uses Qt Graphics View Framework for drawing, therefore QApplication must be used.
QApplication app(argc, argv);
QQuickView viewer;
// The following are needed to make examples run without having to install the module
// in desktop environments.
#ifdef Q_OS_WIN
QString extraImportPath(QStringLiteral("%1/../../../../%2"));
#else
QString extraImportPath(QStringLiteral("%1/../../../%2"));
#endif
viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
QString::fromLatin1("qml")));
//***** [Solve] FORCE THE MODULE TO BE IMPORTED.
QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QWindow::close);
qDebug() << viewer.engine()->importPathList();
viewer.setTitle(QStringLiteral("QML Axes"));
viewer.setSource(QUrl("qrc:/qml/qmlaxes/main.qml"));
viewer.setResizeMode(QQuickView::SizeRootObjectToView);
viewer.show();
return app.exec();
}
[Output through qDebug()]
("/home/snjee/workspace_qt/maxelecPrjs/build-maxCoffeeTdsMeterApp-Desktop_Qt_5_15_2_GCC_64bit-Debug", "qrc:/qt-project.org/imports", "/opt/Qt/5.15.2/gcc_64/qml")
You can find the answer in the built-in "QML Axes" example source.

qt quick 2 printing with console

I can't figure out how to print with console.log inside a qt quick application.
I have this .pro file:
TEMPLATE = app
QT += qml quick
CONFIG += c++11
CONFIG += console
SOURCES += main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Default rules for deployment.
include(deployment.pri)
this is main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
this is main.qml:
import QtQuick 2.5
import QtQuick.Window 2.0
Window {
visible: true
Text {
anchors.centerIn: parent
text: "Hello World"
}
Component.onCompleted: console.log("foo")
}
Why it doens't print "foo"?
solved it was caused by the fact that Fedora has *.debug=false inside /etc/xdg/QtProject/qtlogging.ini and that prevents the messages to be printed. To "solve" this it's enough to create the file ~/.config/QtProject/qtlogging.ini with this content:
[Rules]
default=true

Resources