I have 4 qml files and one main.cpp to load qml file.
Is it possible for me to create 1 dll file for those 4 qml file.
And use it in different application if so how to do that.
As already said, there is no need for embedding qml files only in a library. But of course you have the right to do all you want, even that. I know at least 2 ways to do that:
1. Create binary resource file
Prepare resource file containing qml files and then compile it:
rcc -binary plugin.qrc -o plugin.rcc
Now you can include this file into your application :
QResource::registerResource("plugin.rcc");
and use it as regular qrc file:
QResource::registerResource(qApp->applicationDirPath() + "/plugin.rcc");
QQuickView *view = new QQuickView();
view->setSource(QUrl("qrc:/qml/myfile.qml"));
Here qml/ is prefix in resource file.
2. Shared libraryAnother way is to create a shared library containing the same resource file. For example your plugin's shared library implements following interface:
interface.h
#ifndef PLUGIN_INTERFACE_H
#define PLUGIN_INTERFACE_H
#include <QString>
#include <QObject>
class PluginInterface
{
public:
virtual ~PluginInterface() {}
virtual QByteArray getQML(const QString &name) = 0;
};
#define PluginInterface_iid "org.qt-project.PluginInterface"
Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)
#endif
and its implementation is:
QByteArray PluginImpl::getQML(const QString &name)
{
QFile file(":/qml/" + name);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return QByteArray();
return file.readAll();
}
Now, in your application you load your plugin and get its resource as a string:
QDir pluginsDir(qApp->applicationDirPath());
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath("plugin.dll"));
QObject *plugin = pluginLoader.instance();
if (plugin) {
PluginInterface *pluginInstance = qobject_cast<PluginInterface *>(plugin);
if (pluginInstance) {
QByteArray content = pluginInstance->getQML("file1.qml");
QQuickView *view = new QQuickView();
QQmlComponent component(view->engine());
component.setData(content, QUrl());
QQuickItem *childItem = qobject_cast<QQuickItem*>(component.create());
childItem->setParentItem(view->contentItem());
QWidget *container = QWidget::createWindowContainer(view);
container->setFocusPolicy(Qt::TabFocus);
ui->verticalLayout->addWidget(container);
}
}
But pay attention, when you deploy your application you anyway have to copy all qml system files, like #QTPATH/qml/QtQml, #QTPATH/qml/QtQuick.2, #QTPATH/qml/QtQuick.2 etc.
Links:
Resource compiler
Same theme
Plugin example
Have a look at the documentation for QML Modules
There are options for QML-only modules, C++ only and mixed mode.
Related
I have a very simple test project under Windows 7 with the following code only on the main window:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSettings>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings settings("./conf.ini");
settings.setValue("testconf", 123);
settings.sync();
}
MainWindow::~MainWindow()
{
delete ui;
}
I just made a project from scratch and the MainWindow is empty. For reference, I add the .pro content, though it should not be relevant:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qsettingstest
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
I tried different paths for the settings file, using QStandardPaths::writableLocation(QStandardPaths::DataLocation), existing directories e.g. "c:\mydir". I tried also replacing QSettings settings("./conf.ini"); with QSettings *psettings = new QSettings("./conf.ini");, call sync or not call it, but:
The file is not created or modified (in case I create it manually before). Why?
You use 1 QString constructor for QSettings. This will set the Organization Name, not the file name (see https://doc.qt.io/qt-5/qsettings.html#QSettings, application name is defaulted to an empty QString).
This will store/read the settings from the windows registry. Check for a ./conf.ini key there
You want to use the QSetting constructor taking a filename and a format (see https://doc.qt.io/qt-5/qsettings.html#QSettings-3):
QSettings settings("./conf.ini", QSettings::IniFormat);
In the new Qt 5.15.0 there is a new declarative way to register C++ types for usage in QML. I followed the steps given in Qt Help (https://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html#registering-an-instantiable-object-type) but it givens to me the following error:
/.../randomnumbergenerator.h:10: error: ‘QML_ELEMENT’ does not name a type
QML_ELEMENT
^~~~~~~~~~~
The class's definition is, for the moment:
#ifndef RANDOMNUMBERGENERATOR_H
#define RANDOMNUMBERGENERATOR_H
#include <QObject>
#include <QRandomGenerator>
class RandomNumberGenerator : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
public:
explicit RandomNumberGenerator(QObject *parent = nullptr);
signals:
};
#endif // RANDOMNUMBERGENERATOR_H
EDIT: I already added to the .pro file the following:
CONFIG += c++11 qmltypes
QML_IMPORT_NAME = SimpleRng
QML_IMPORT_MAJOR_VERSION = 1
As they point out in the Qt forum you have to include <qml.h> (or <QtQml>)
The preconditions section of the documentation you quoted states that
All the macros mentioned below are available from the qqml.h header. You need to add the following code to the files using them in order to make the macros available:
#include <QtQml/qqml.h>
That seems to be the canonical answer and may avoid the issues that #lateus mentioned in comments.
I am constantly running into problems while using the Q_OBJECT macro: (I use QT Creator 2.8.1 / Qt 4.8.4) I asked before but it seems to be leading to even more trouble. Can anybody help me? I am totally lost .
I have a huge C++ program with about 50+ classes to adapt to new needs.
Now I created a new (very simple) parent-class and 3 child classes in a new directory within the src-directory. To do so I used the template Qt->Qt Designer Form Class.( I did that because this automatically implements Q_OBJECT even though I do not need a *.ui-file. I then removed all concerning ui-Fileand the ui-file itself))
When I run my program I always get lots of „ undefined reference to vtable for“ ..-errors. When I remove all Q_OBJECT my program runs OK. But then I am not able to use signal-slots which I would need later on.
I looked it up in the internet and found out it has something to do with the .pro-file/.o-Files in my build-directory. I (several times) tried to delete all .o-Files including the .pro.user and compile again. Sometimes I still got the error, sometimes not.
This is my code ( the 3 child classes are the same at the moment):
geometry.h:
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <QMetaType>
#include <QWidget>
#include <QObject>
#include <QDebug>
class Geometry
{
Q_OBJECT
protected:
public:
Geometry();
virtual ~Geometry(void) {}
virtual void write_LNE();
//Q_DECLARE_METATYPE(Geometry);
#endif // GEOMETRY_H
-
geometry.cpp:
#include "geometry.h"
Geometry::Geometry()
{ qDebug() << "Constructor: hier ist Geometry"; }
void Geometry::Haupt()
{ qDebug() << " Das hier ist die Haupt von Geometry ....." ; }
void Geometry::write_LNE(){}
-
Geo_1PF.h:
#ifndef GEO_1PF_H
#define GEO_1PF_H
#include "geometry.h"
class Geo_1PF : public Geometry
{
Q_OBJECT
public:
Geo_1PF();
~Geo_1PF() {}
virtual void write_LNE();
};
//Q_DECLARE_METATYPE(Geo_1PF);
#endif // GEO_1PF_H
Geo_1PF.cpp:
#include "Geo_1PF.h"
Geo_1PF::Geo_1PF()
{
}
I found the advice to do qmake manually. I never used qmake manually.
How and from which directory do I do this ? Exactly what do I write qmake …….?
Is it correct to use the template Qt->Qt Designer Form Class to create these classes?
Do I have to create the classes in another directory?
Are there any additional entries I have to make in the +.pro-File
and where in the file do they have tob be put?
Do I have to change anything in my makefile? And if so what?
Thank you
If you use Qt Creator:
Everytime you create a class using Q_OBJECT,
Build → Run qmake
Build → Rebuild All
To use the QOBJECT macro in your class you need to extend QObject.
class MyObject: public QObject
{
Q_OBJECT
public:
MyObject (QObject *_parent);
.....
};
I have 4 qml files and one main.cpp to load qml file.
Is it possible for me to create 1 dll file for those 4 qml file.
And use it in different application if so how to do that.
As already said, there is no need for embedding qml files only in a library. But of course you have the right to do all you want, even that. I know at least 2 ways to do that:
1. Create binary resource file
Prepare resource file containing qml files and then compile it:
rcc -binary plugin.qrc -o plugin.rcc
Now you can include this file into your application :
QResource::registerResource("plugin.rcc");
and use it as regular qrc file:
QResource::registerResource(qApp->applicationDirPath() + "/plugin.rcc");
QQuickView *view = new QQuickView();
view->setSource(QUrl("qrc:/qml/myfile.qml"));
Here qml/ is prefix in resource file.
2. Shared libraryAnother way is to create a shared library containing the same resource file. For example your plugin's shared library implements following interface:
interface.h
#ifndef PLUGIN_INTERFACE_H
#define PLUGIN_INTERFACE_H
#include <QString>
#include <QObject>
class PluginInterface
{
public:
virtual ~PluginInterface() {}
virtual QByteArray getQML(const QString &name) = 0;
};
#define PluginInterface_iid "org.qt-project.PluginInterface"
Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)
#endif
and its implementation is:
QByteArray PluginImpl::getQML(const QString &name)
{
QFile file(":/qml/" + name);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return QByteArray();
return file.readAll();
}
Now, in your application you load your plugin and get its resource as a string:
QDir pluginsDir(qApp->applicationDirPath());
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath("plugin.dll"));
QObject *plugin = pluginLoader.instance();
if (plugin) {
PluginInterface *pluginInstance = qobject_cast<PluginInterface *>(plugin);
if (pluginInstance) {
QByteArray content = pluginInstance->getQML("file1.qml");
QQuickView *view = new QQuickView();
QQmlComponent component(view->engine());
component.setData(content, QUrl());
QQuickItem *childItem = qobject_cast<QQuickItem*>(component.create());
childItem->setParentItem(view->contentItem());
QWidget *container = QWidget::createWindowContainer(view);
container->setFocusPolicy(Qt::TabFocus);
ui->verticalLayout->addWidget(container);
}
}
But pay attention, when you deploy your application you anyway have to copy all qml system files, like #QTPATH/qml/QtQml, #QTPATH/qml/QtQuick.2, #QTPATH/qml/QtQuick.2 etc.
Links:
Resource compiler
Same theme
Plugin example
Have a look at the documentation for QML Modules
There are options for QML-only modules, C++ only and mixed mode.
I am having problems with launching Nokia's own video player from my application that I just don't seem to be able to solve.
My first attempt included calling
Qt.openUrlExternally(url)
from QML and that seemed to do the trick just fine, except that it opened the browser every time and used it instead of the video-suite (native player).
Next I tried cuteTube -approach where I start new process like this:
QStringList args;
args << url;
QProcess *player = new QProcess();
connect(player, SIGNAL(finished(int, QProcess::ExitStatus)), player, SLOT(deleteLater()));
player->start("/usr/bin/video-suite", args);
That worked, except that it required video-suite to be closed upon calling player->start, otherwise it did nothing.
My third attempt involved starting the video-suite via QDBus, but that didn't work any better:
QList<QVariant> args;
QStringList urls;
urls << url;
args.append(urls);
QDBusMessage message = QDBusMessage::createMethodCall(
"com.nokia.VideoSuite",
"/",
"com.nokia.maemo.meegotouch.VideoSuiteInterface",
"play");
message.setArguments(args);
message.setAutoStartService(true);
QDBusConnection bus = QDBusConnection::sessionBus();
if (bus.isConnected()) {
bus.send(message);
} else {
qDebug() << "Error, QDBus is not connected";
}
The problem with this is that it requires video-suite to be up and running - autoStartService parameter didn't help either. If video-suite isn't running already, the call opens it just fine but, alas, no video starts to play.
Eventually I tried using also VideoSuiteInterface, but even having the program compile with it seemed to be difficult. When I eventually managed to compile and link all relevant libraries, the results didn't differ from option 3 above.
So, is there a way to use either VideoSuiteInterface directly or via DBus so that it would start video playback regardless of the current state of the application?
The solution was actually simpler than I really thought initially; the VideoSuiteInterface -approach worked after all. All it took was to use it properly. Here are the full sources should anyone want to try it themselves.
player.h:
#ifndef PLAYER_H
#define PLAYER_H
#include <QObject>
#include <maemo-meegotouch-interfaces/videosuiteinterface.h>
class Player : public QObject {
Q_OBJECT
private:
VideoSuiteInterface* videosuite;
public:
Player(QObject *parent = 0);
Q_INVOKABLE void play(QString url);
};
#endif // PLAYER_H
player.cpp:
#include "player.h"
#include <QObject>
#include <QStringList>
#include <QtDeclarative>
Player::Player(QObject *parent) : QObject(parent) {}
void Player::play(QString url) {
QList<QVariant> args;
QStringList urls;
urls << url;
args.append(urls);
videosuite = new VideoSuiteInterface();
videosuite->play(urls);
}
In addition you may want to connect some signals to make the UI more responsive, but basically that should do the trick.
Finally, you need to remember to add following to your .pro file and you are good to go:
CONFIG += videosuiteinterface-maemo-meegotouch