Images not displaying in Qt application packaged with linuxdeployqt - qt

I have a sample project at https://github.com/jh3010-qt-questions/large_qrc
If I run the app from Qt Creator, I get a window which looks like the one below.
However, if I package the app with linuxdeployqt, only the bottom image on the window displays. It is loaded directly from disk. The top image is from a .qrc which should have been attached to the executable, but it does not appear.
My directory structure follows the recommendation from linuxdeployqt
$ tree usr
usr
├── bin
│   ├── image_assets
│   │   └── original_image_png
│   └── large_qrc
├── lib
└── share
├── applications
│   └── large_qrc.desktop
└── icons
└── hicolor
└── 256z256
└── apps
└── large_qrc.png
I build the app image by doing:
linuxdeployqt usr/share/applications/large_qrc.desktop -appimage -qmake=/home/jamesh/Qt5.12.10/5.12.10/gcc_64/bin/qmake -qmldir=/home/jamesh/depot_qt/questions/large_qrc
I can double click on the resulting large_qrc-x86_64.AppImage executable from the Ubuntu GUI. The application launches successfully, but the top image does not show up.
What needs to be changed so QML Image can access the image in the .qrc?
A secondary question is whether or not there is a better way to handle the images in image_assets. It seems a bit odd to copy them into the bin folder, but perhaps that is a best practice in this situation.
If it matters, I am using Ubuntu 20.04
My project file is:
QT += quick
CONFIG += c++11
image_assets.files = $$PWD/image_assets
image_assets.path = $$OUT_PWD
COPIES += image_assets
SOURCES += \
main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
qml.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>drawing.svg</file>
</qresource>
</RCC>
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column {
Image {
width: 200
height: 200
fillMode: Image.PreserveAspectFit
source: "qrc:drawing.svg"
}
Image {
width: 200
height: 200
fillMode: Image.PreserveAspectFit
source: "file:///" + applicationDirPath + "/image_assets/original_image_png"
}
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty( "applicationDirPath", QGuiApplication::applicationDirPath() );
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();
}
large_qrc.desktop
[Desktop Entry]
Type=Application
Name=large_qrc
Comment=The best Qt Application Ever
Exec=large_qrc
Icon=large_qrc
Categories=Office;
This should be the output and is when I run the program from Qt Creator.

Related

QML/WebGL - How to stop DefaultFileDialog from returning unusable paths on Windows?

Problem description
When building a QML application on Windows for the desktop that contains a FileDialog, the default Windows file dialog is shown. This one works as expected, returning a path to the selected file or folder that has a prefix (file:///) before the path. Only once WebGL comes into play, the problem appears.
Building for the WebGL platform and connecting via browser will default the file dialog to DefaultFileDialog, which behaves drastically different upon selection of (sub-)directories. Lets say we start out with this path in the dialog (clipped to focus on the ROI):
After selecting a subdirectory (single click):
Another click enters that directory and replaces the path with:
If another selection is taken in the subdirectory, we finally lose the drive letter:
The path is something that I expect to work on Linux which might be the reason why I could not find any additional information on this behavior. Additional steps into subdirectories do not break the path further:
My search so far
I have google'd it, searched Stack Overflow and tried to regex my way through this problem, but so far, no luck.
Question
Is there a way to stop DefaultFileDialog instances from optimizing my path selections into uselessness on Windows? Ideally, I'd like to keep the system file dialog when not running the application for WebGL, but this is no hard requirement for me.
EDIT: #mike510a revealed other requirements that I missed:
The drive letter may be any valid one, as within the dialog, the drive can be changed. Therefore hardcoding a drive letter to replace the one lost within the dialog does not work.
Due to the unknown number of steps taken before accepting a file or folder, it cannot be assumed that the drive letter was already cut from the returned QString.
Sample code
Modify a project created by QtCreator (4.13.2 in my case, empty QtQuick project).
# autogenerated
QT += quick
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
app.setOrganizationName("Something"); // modified to avoid QML warning
app.setOrganizationDomain("Something.else"); // modified to avoid QML warning
QQmlApplicationEngine engine;
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();
}
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Dialogs 1.2
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
Window {
width: 640
height: 480
minimumHeight: 320
minimumWidth: 480
visible: true
title: qsTr("Hello World")
color: "grey"
RowLayout {
anchors.fill: parent
Label {
text: "File path:"
Layout.column: 0
}
TextEdit {
id: pathTextEdit
readOnly: true
clip: true
Layout.column: 1
Layout.fillWidth: true
Rectangle {
z: -1
anchors.fill: parent
radius: 3
color: "white"
}
}
Button {
text: "Select file"
Layout.column: 2
onClicked: {
pathSelection.visible = true
}
}
}
FileDialog {
id: pathSelection
visible: false
width: 300
height: 300
selectFolder: true
onAccepted: {
pathTextEdit.text = folder
}
}
}
I'm pretty sure that because the WebGL platform uses a different schema than the Windows filesystem directory structure, you will get weird folders. You can use the schema file:// to translate URLS into pointers to files on the local machine, You can use the folder property along with file:///C:/Users/whatever or do the following...
To grab the operating System's underlying filesystem's locations, you can use the folder property with the value shortcuts.home as stated here: https://doc.qt.io/qt-5/qml-qtquick-dialogs-filedialog.html
FileDialog {
id: pathSelection
visible: false
width: 300
height: 300
selectFolder: true
// point to an operating system location and you should get
// a usable URL
folder: shortcuts.home
onAccepted: {
pathTextEdit.text = folder
}
}
With the help of Qt Support, a solution could be found. The issue responsible for the behavior is found in DefaultFileDialog.qml, more specifically, the function dirDown. It is fixable by replacing
root.folder = "file://" + path
with
root.folder = root.pathToUrl(path)
and rebuilding Qt afterwards. The entire patch reads like this:
--- a/src/dialogs/DefaultFileDialog.qml
+++ b/src/dialogs/DefaultFileDialog.qml
## -115,7 +115,7 ## AbstractFileDialog {
function dirDown(path) {
view.selection.clear()
- root.folder = "file://" + path
+ root.folder = root.pathToUrl(path)
}
function dirUp() {
view.selection.clear()
This patch was submitted for inclusion with Qt 5.15.3.

How to set relative path instead of absolute

I am using Qt Quick Application project in QT 5.2.1 in Linux Mint 13 and I want use relative path to my audio files, which are located in sounds folder of my project folder.
Here is my
main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import QtMultimedia 5.0
Window {
visible: true
width: 360
height: 360
Audio{
id: sound
source: "sounds/1.mp3" //doesn't work
source: "file:../sounds/1.mp3" //also doesn't work
source: "file:/home/vlado/Qt projects/test521/sounds/1.mp3" //this works
}
MouseArea {
anchors.fill: parent
onClicked: {
sound.play()
}
}
Text {
text: qsTr("Play Sound")
anchors.centerIn: parent
}
}
Doesn't work means, that there is following error:
GStreamer; Unable to play - "" Error: "No URI set"
As you can see, everything is OK, if I use absolute path, but I would like to deploy this application and installation folder then will be different. That's why I want to use relative path.
Here is my
test521.pro
TEMPLATE = app
QT += qml quick
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)
Here is
my main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml")));
return app.exec();
}
How to set relative path instead of absolute?
Edit: Solution for QML: how to specify image file path relative to application folder doesn't work for me.

Rectangle as a root element in QML

I use Qt 5.5.0 MSVC 2013, 32bit.
I want to create minimal QtQuick application. When I choose New Project - Qt Quick Application I got project with 2 QML files: main.qml and MainForm.ui.qml. Since I do not need them, I delete second one and paste following to main.qml:
Import QtQuick 2.4
Rectangle{
id: root
visible: true
color: "gray"
width: 400
height: 800
}
But when I run project I got nothing. I see application in Task Manager but there is no application window.
Question: Is it possible to create .qml file with Rectangle as a root element?
Solution was found at official Qt Forum.
The template for creating Qt Quick Application adds QQmlApplicationEngine to launch the QML. But QQmlApplicationEngine dont work directly with Rectangle or Item as root element but requires any window like Window or ApplicationWindow.
So to make it work for Rectangle use QQuickView instead of QQmlApplicationEngine.
I changed content of main.cpp to
#include <QGuiApplication>
#include <QQuickView>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView *view = new QQuickView;
view->setSource(QUrl("qrc:/main.qml"));
view->show();
return app.exec();
}
and it solved my problem.

I got errors: "QQmlApplicationEngine failed to load component" and "qrc:/main.qml:-1 File not found"

I created a Qt Widgets application, then added a qml named "main.qml" to it. My files are dialog.cpp, dialog.h, dialog.ui, main.cpp, untitiled9.pro, main.qml in qml.qrc
main.cpp:
#include "dialog.h"
#include <QApplication>
#include <QQmlApplicationEngine>
#include<QtQml>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
// w.show();
QQmlApplicationEngine engine;
// engine.load(QUrl(QStringLiteral("qrc://main.qml")));
engine.load(QUrl::fromLocalFile("qrc:///main.qml"));
return a.exec();
}
I wrote QT += qml quick widgets in untitled9.pro.
I didn't modified other codes, how did this happen?
This is my first question in stackoverflow, I try to make my question clear.
QUrl::fromLocalFile will build a local file based url. So, just remove "qrc:///" in the code. Copy main.qml into build target directory if necessary.
Sample code:
engine.load(QUrl::fromLocalFile("main.qml"));

Qt c++ gui desktop app Phonon

I am running on ubuntu 13.10 64bit with installed Qt Creator also i have installed libphonon-dev
my code looks like this:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <phonon/phonon> // yes directory /usr/include/phonon exists
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Phonon::MediaObject *music = Phonon::createPlayer(Phonon::MusicCategory, Phonon::MediaSource("/home/erik/Downloads/Bob_Marley-No_Woman_No_Cry.mp3"));
music->play();
}
MainWindow::~MainWindow()
{
delete ui;
}
I am getting 10 same errors:
/usr/include/phonon/phonon:12: In file included from
/usr/include/phonon/phonon:12:0,
/home/erik/QtProjs/QtPlayer/mainwindow.cpp:3: from
../QtPlayer/mainwindow.cpp:3: /usr/include/phonon/effectwidget.h:28:
error: QtGui/QWidget: No such file or directory #include
<QtGui/QWidget> ^ /usr/include/phonon/effectwidget.h
any other project file is default (mainwindow.h, mainwindow.ui, main.cpp)
Yesterday i have made a simple text editor(not from example), but i cant get through this error.
Thankyou
Take a look at this question. It can be similar to your case if you're building a Qt 4 project with Qt 5.

Resources