Phonon::MediaSource, cannot use resource as media source - c++

with QT 4.6, I am trying to access a wav file in my QResource file to use as the media source of a media player and it does not work:
Phonon::MediaObject *music;
music=Phonon::createPlayer(Phonon::MusicCategory,Phonon::MediaSource(:/FPS_sounds/arming.wav));
music->play();
If I put the direct path it works. I have been successful at using resources in other parts of my program so there does not seem to be a problem there and the Qt doc says I can use QResource for this type of operation. Is this a bug or am I missing something?

This one gave me a good scratch as well.
But lo and behold, it can be implemented easily using a temporary file:
{
QTemporaryFile f;
f.open();
QResource res(":/badger");
f.write((char*)res.data(),res.size());
f.flush();
f.setAutoRemove(true);
f.close();
QString fn = f.fileName();
QSound::play(fn);
}

Related

How to access Qt resource data from non-Qt functions

As I understand it, the way to packages non-code resources such as data files in a Qt app is using the resource system. However, what if I want to access a resource using a non-Qt function. For example, I may have a .txt or .csv file with some application data that I want to accessing using ifstream. It doesn't seem to work to use the ": ..." syntax in place of a filename for non-Qt functions and classes. Is there a separate workflow for packaging data used by non-Qt functions in an app?
I'm using OSX, but I would assume these issues are platform independent.
The sole purpose of the Qt resource system is to bundle data within the executable itself. If you wish not to integrate the data in the executable, then you simply must not use the resource system.
On mac, if you wish to add "data.txt" from project source to your application bundle, but not to the executable itself, add the following to your .pro file:
mac {
BUNDLE = $$OUT_PWD/$$TARGET$$quote(.app)/Contents
QMAKE_POST_LINK += ditto \"$$PWD/data.txt\" \"$$BUNDLE/Resources/\";
}
Given the above project file, use the QCoreApplication::applicationDirPath() for a path useful in getting to the file:
#include <QCoreApplication>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << QCoreApplication::applicationDirPath();
QFile data(QCoreApplication::applicationDirPath() + "/../Resources/data.txt");
if (data.open(QIODevice::ReadOnly | QIODevice::Text))
qDebug() << data.readAll();
return 0;
}
In the above example, the Resources folder has nothing to do with the Qt resource system. It's simply a naming convention in OS X application bundles. We're not using the Qt resource system here.
If you wish to use the Qt resource system and access the resource data directly and not through a QFile, the QResource class provides access to resources that are bundled in the executable.
If the code under your control insists on using ifstream for data input, then it's artificially limited and should be fixed. It should use istream instead, as that class can be backed by anything, not necessarily a file. If it's code that you don't control, you could set up the ifstream on a QLocalSocket.
You can map the constant QResource::data() to an input stream via a stream buffer.
If the resource isCompressed(), then you need to first decompress it to a temporary area. You can also disable resource compression to avoid the decompression step. You can use a whole-executable compressor like upx instead - by the time your code runs, everything will be already decompressed and ready to use.
You can copy the resource file into a temporary folder. To do this, use a QTemporaryDir which creates a temporary folder and deletes it automatically when the program is finished. To access the path of that folder, use the QTemporaryDir::path() method. Here is an example of how you can use it:
#include <QTemporaryDir> //You need to include this header
QTemporaryDir temporaryDir;
//Copy the resource file into the temporary folder
QFile::copy(":/exampleprefix/examplefile.txt", temporaryDir.path() + "/examplefile.txt");
//Read the file
std::ifstream fileStream(QString(temporaryDir.path() + "/examplefile.txt").toLatin1().data());
//etc
What about opening the resource file with a QFile object, wrapping this with a QDataStream object, and wrapping this with a boost::iostreams::stream object, which derives from a specialization of std::basic_istream? Sounds complicated, but does not need too many lines of code, see this answer.

Exporting SVG into the local Resource directory

I am trying to reach the qt resource folder without success. It works if I export into an other folder like C:\\Temp\\18_25_21_18_09_2014.svg, but it doesn't work if I use an URL like :/Temp/18_25_21_18_09_2014.svg.
Here is the code:
QString fileName(":/Temp/Temp" + QDateTime(QDateTime::currentDateTime()).toString("hh_mm_ss_dd_MM_yyyy") + ".svg");
QSvgGenerator generator;
generator.setFileName(fileName);
generator.setSize(this->size());
generator.setViewBox(QRect(QPoint(0,0), this->size()));
generator.setTitle(tr("bubble_svg"));
generator.setDescription(tr("bubble_svg"));
_painter.begin(&generator);
_painter.setRenderHint(QPainter::Antialiasing);
_painter.setRenderHint(QPainter::HighQualityAntialiasing);
this->render(&_painter);
_painter.end();
Also I created a prefix called Temp and a folder called Temp.
It looks like that also QDirIterator can reach the folder, only the QSvgGenerator couldn't.
QDirIterator it(":/Temp/Temp", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
qDebug() << "FILE FOUND " << it.next();
}
The result of this part of code:
FILE FOUND ":/Temp/Temp/18_35_19_18_09_2014.svg"
I appreciate every idea. Thanks for dropping by and taking time with the questions!
Ok, I understood and post it as answer.
Unfortunately it is impossible. Qt Resource System forbid this. As documentation said:
The Qt resource system is a platform-independent mechanism for storing binary files in the application's executable. It means that resources are read only, thuis files compiled into the executable, you can't write it because this files storing in your exe file. Especially an executable can’t modify itself while it is running. You’ll have to re-compile the QRC file (using RCC) and then re-build the EXE file, if one of the resources has changed.
As you can see, you should provide another way to storing and using your files.
I hope it was useful for you.

QT Application crashes using QSettings instance via qApp->property

Aloha,
Im developing a small "ServerManager" for myself using QT (C++).
Anything worked till this point:
I use QSettings to store all relevant Settings (like Server, installed Plugins and so on).
As I didn't want to instanciate the QSettings class everywhere I have to use it, i thought i could try to instanciate it one time in the main.cpp and make it available using the qApp->setProperty() method.
How i setup the QSettings class:
QSettings* Settings = new QSettings(".\\Settings.ini", QSettings::IniFormat);
How i "publish" it:
qApp->setProperty("Settings", QVariant::fromValue<QSettings*>(Settings));
And finally. If i use it like this:
QSettings* Settings = qApp->property("Settings").value<QSettings*>();
Settings->beginGroup("Servers");
The whole application crashed with an SIGSEGV signal (Segmentation fault).
Stacktrace: Stacktrace http://host-it.tk/Upload/53ab11da0d706/37.PNG
I really got no clue why this happens.
Maybe the solution is obvious, but this is my "first real" Application.
It seems like I got the well known "tunnel view".
Thanks for your time!
Relevant code parts: http://pastebin.com/VzZ9uuJi
QT-Version: 5.2.1
Since a QSettings* is not a usual QVariant type, you would have to declare it.
Q_DECLARE_METATYPE(QSettings*);
This is not the usual way to share QSettings, though. Since it is in INI format, consider just passing the location to the INI file with absolute paths instead:
QFileInfo path(".\\Settings.ini");
qApp->setProperty("SettingsLocation", path.absoluteFilePath());
Then later:
QSettings Settings(qApp->property("SettingsLocation").toString(), QSettings::IniFormat);
Settings.beginGroup("Servers");

How to copy qrc resource file into filesystem?

I wonder how to copy file that is embeded into app qrc into fs? Stuff like
QFile::copy("qrc:/assets/files/my.file" , "C:/my.file");
seems not to work. Why and how to make it to?
You don't need the qrc, resources start with a :
eg QFile myFile(":/data/data.xml");
PS: I'm not sure how QFile treats case sensitiveness on resource filenames. For best portability you might want to make sure the case matches whatever is in your qrc file.

Problem with QHttp example qt 4.4.3

I'm trying to use QHttp for an update app. But there is a problem for me which I can't solve.
I try to download a file (works perfectly) but if there is no connection to the internet, the file is created but has 0 bytes. My old file is then overwritten with the empty file, which is not so good for the application trying to use the file. What I need is to check if the computer is connected to the internet.
Note: proxy may set. I used this example from Qt's homepage.
You should switch to the QNetworkAccessManager as Mike Suggested, here is an example of a slot on the finished() signal:
void ApplicationUpdate::replyFinishedhttpGetChangeLog(QNetworkReply* myReply) {
if (myReply->error() != QNetworkReply::NoError)
{
QByteArray returnedData = myReply->readAll();
if (returnedData.size() > 0) {
if( m_fileChangeLog->exists() )
{
m_fileChangeLog->close();
m_fileChangeLog->remove();
}
m_fileChangeLog->open(QIODevice::ReadWrite);
QDataStream out( m_fileChangeLog );
out.writeRawData(returnedData.data(), returnedData.size());
m_fileChangeLog->flush();
m_fileChangeLog->close();
}
}
}
Firstly, you should probably now be using QNetworkAccessManager rather than QHttp.
Using either of them, you should do a dummy query to a site you pretty much always know will be up (e.g. http://www.google.com/) and use that as a test to see if you have an internet connection.
A better way of doing this would be instead to use QNetworkAccessManager to read into a QByteArray and then check it isn't empty before writing to your file.
Whenever you write a file that might already exist, you should create a QTemporaryFile first, then, after successful download, rename it to the final name.
i ran into the same problem, after a bit of poking around, I've isolated the problem down to the project configuration file (.pro), in the broken configuration I was linking the networking library explicitly with the statement : "LIBS += -lQtNetwork". In the working configuration, I used the more formal (and qt compilant) approach of delcaring what Qt components are included in the project, like so: "QT = core gui network xml", adjust accordingly for your sitiation, the netowkring slots did not work on windows when explicitly linked but did work on linux. Using the qt compilant approach works on both platforms.