Can't enable debug context for QQmlApplicationEngine - qt

I want to enable OpenGL logging in Qt. My code:
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSurfaceFormat>
#include <QOpenGLContext>
#include <QOpenGLDebugLogger>
QSurfaceFormat createSurfaceFormat() {
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setOption(QSurfaceFormat::DebugContext);
return format;
}
void initGLLogging(QQmlApplicationEngine& engine) {
QOpenGLContext *ctx = QOpenGLContext::currentContext();
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(&engine);
logger->initialize();
qDebug() << "can gl log? " << ctx->hasExtension(QByteArrayLiteral("GL_KHR_debug"));
QObject::connect(logger, &QOpenGLDebugLogger::messageLogged,
[&](const QOpenGLDebugMessage &debugMessage) {
qDebug() << debugMessage;
}
);
logger->startLogging();
}
int main(int argc, char *argv[])
{
QSurfaceFormat::setDefaultFormat(::createSurfaceFormat());
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
::initGLLogging(engine);
return app.exec();
}
main.qml:
import QtQuick 2.6
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
}
The output, after building in debug mode and running in the debugger, is:
QOpenGLDebugLogger::initialize(): the current context is not a debug context:
this means that the GL may not generate any debug output at all.
To avoid this warning, try creating the context with the
QSurfaceFormat::DebugContext surface format option.
can gl log? true
Any idea why it's failing?
Note: I'm using ANGLE-mode in all Qt apps on my system, enabled via an env var, because otherwise they break in all kinds of ways. That's very likely to be related to the problem, but I can't do without this setting.

Related

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();
}

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.

Setting LocalStorage Location via setOfflineStoragePath

I'm trying to set the LocalStorage location (sqlite db) for my QML application but once i rebuild and run the application i still can't see the subfolder, INI file and the sqlite DB created on the desired location (in a subfolder within the resources folder). Here is what's in my main file.
Appreciate any one could pint what's I'm doing wrong here?
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QString>
#include <QDebug>
#include <QDir>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
//engine.setOfflineStoragePath("qrc:/");
auto offlineStoragePath = QUrl::fromLocalFile(engine.offlineStoragePath());
engine.rootContext()->setContextProperty("offlineStoragePath", offlineStoragePath);
QString customPath = "qrc:/OffLineStorage";
QDir dir;
if(dir.mkpath(QString(customPath))){
qDebug() << "Default path >> "+engine.offlineStoragePath();
engine.setOfflineStoragePath(QString(customPath));
qDebug() << "New path >> "+engine.offlineStoragePath();
}
return app.exec();
}
By looking at the code snippet in your question, everything looks fine.
Anyway, you should verify if the following line actually returns true as you expect:
dir.mkpath(QString(customPath)
If no, the body of the if statement isn't executed in any case, thus setOfflineStoragePath is never invoked.
As a hint, using qrc:/OffLineStorage as a path for your storage doesn't seem to be a good idea. I'm not sure it will work once in the production environment (to be checked, it sounds strange, but it could work).
Try use engine.setOfflineStoragePath before engine.load.
Using qrc:/OffLineStorage as a path for your storage doesn't seem to
be a good idea. I'm not sure it will work once in the production
environment
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QString>
#include <QDebug>
#include <QDir>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QString customPath = "qrc:/OffLineStorage";
QDir dir;
if(dir.mkpath(QString(customPath))){
qDebug() << "Default path >> "+engine.offlineStoragePath();
engine.setOfflineStoragePath(QString(customPath));
qDebug() << "New path >> "+engine.offlineStoragePath();
}
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
engine.clearComponentCache();
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}

Qt connect - object emits signal before connect is issued

I have following main.cpp:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "database/uepeoplemodel.h"
#include "core/uestatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now, inside main.cpp I create two objects from classes:
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
and I connect signal from UePeopleModel to slot in ueApplicationStatus:
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
The problem is when uePeopleModel is created, the signal is emmited inside constructor:
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent),
QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
} // if
this->ueDatabase().setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
this->ueDatabase().setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
this->ueDatabase().setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
this->ueDatabase().setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
/*
if(this->lastError().isValid())
qDebug() << this->lastError();
*/
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
// qDebug() << this->ueDatabase().lastError();
}
// qDebug() << this->ueDatabase().connectionNames();
} // default constructor
before connect is issued and therfore ueApplicationStatus object does not catch is with slot. Does anyone has idea how to get rid of this situation?
You shouldn't use the constructor to open the connection with the database.
Use the constructor only to instantiate other classes, initialize variables, allocate memory and so on.
In your case, your constructor should be used to initialize the database, but you could create another method with:
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
}
This method would be called after the connect you have in your main.cpp.
I've solved the problem by adding method void ueConnectToDatabase() and moved the content of constructor into it and redefined main.cpp as:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
uePeopleModel->ueConnectToDatabase();
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now the object is created, signal and slot connected and AFTER this the connection to database occurs.

QtQuick, how to know if a application was compiled on debug or release mode?

At Qt/C++ there is QT_DEBUG define macro to know when it is compiled at debug or release.
Is there any method to know if is the application running in debug o release mode inside a QML file?
You can use context properties (or QQmlApplicationEngine::setInitialProperties() since Qt 5.14) to expose C++ objects to QML:
#include <QtGui/QGuiApplication>
#include <QQmlContext>
#include <QQuickView>
#include "qtquick2applicationviewer.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
#ifdef QT_DEBUG
viewer.rootContext()->setContextProperty("debug", true);
#else
viewer.rootContext()->setContextProperty("debug", false);
#endif
viewer.setMainQmlFile(QStringLiteral("qml/quick/main.qml"));
viewer.showExpanded();
return app.exec();
}
main.qml:
import QtQuick 2.2
Item {
id: scene
width: 360
height: 360
Text {
anchors.centerIn: parent
text: debug
}
}
It's not possible to determine this purely from within QML.
You need to know it in runtime or in compile time? Macros are used in compile time, QML is executed in runtime, so there are no difference for compiled application between "debug" and "release".
Solution:
Create a class with const property declared in next way:
class IsDebug : public QObject
{
QOBJECT
Q_PROPERTY( IsDebug READ IsCompiledInDebug ) // Mb some extra arguments for QML access
public:
bool IsCompiledInDebug() const { return m_isDebugBuild; }
IsDebug()
#ifdef QT_DEBUG
: m_isDebugBuild( true )
#else
: m_isDebugBuild( false )
#endif
{}
private:
const bool m_isDebugBuild;
}

Resources