How to import Qml plugins lib into another project? - qt

I have a 2 qml files in a lib and I want to export those to another project and was unable to import in my QuickQmlTest project. I want to use those qml files from QmlPlugin lib in QuickQmlTest project. Is there any additional step I need to do ? I have a folder structure
QMLProject
|-- QmlPlugin -(it is lib)
|--QML
|--CustomButton.qml
|-- CustomPolygon.qml
|-- QuickQmlTest - (app)
My QmPlugins.pro looks like this
TEMPLATE = lib
TARGET = QmlPlugin
QT += qml quick
CONFIG += plugin c++11
TARGET = $$qtLibraryTarget($$TARGET)
HEADERS += \
MyPlugin.h
DISTFILES = qmldir \
CustomButton.qml \
CustomPolygon.qml
DESTDIR = $$PWD/lib
And I linked the generated dlls into to the QuickQmlTest.pro using
LIBS += -L$$PWD/../QmlPlugin/lib -lQmlPlugin
INCLUDEPATH += $$PWD/../QmlPlugin
MyPlugin.h
#include <QQmlExtensionPlugin>
#include <QtQml/qqml.h>
class MyItemModel: public QObject
{
Q_OBJECT
Q_PROPERTY(qreal roundingRadius READ roundingRadius WRITE setRoundingRadius)
public:
void setRoundingRadius(const qreal rounding)
{
roundingRadius_ = rounding;
}
qreal roundingRadius() const
{
return roundingRadius_;
}
private:
qreal roundingRadius_{8.0};
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char* uri)override
{
Q_ASSERT(uri == QLatin1String("Components"));
qmlRegisterType<MyItemModel>(uri, 1, 0, "MyItemModel");
}
};
in qmldir I have
module Components
Components 1.0 CustomButton.qml CustomPolygon.qml
plugin QmlPlugin
In the QuickQmlTest (app)
I want to use CustomButton.qml and CustomPolygon.qml in my main.qml
So my main.qml in QuickQmlTest app
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import Components 1.0 //To import the dll from lib
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
CustomPolygon
{
width:60
height:30
}
CustomButton
{
width:60
height:30
}
}
And also I want to see my Custom qml types(CustomButton and CustomPolygon) in Quick Design mode which I am unable to achieve.

Related

My custom C++ plugin is not being consumed by the qml test application

I am new to Qt and learning few of the modules in Qt-Qml from youtube and Qt documentation. I want to create cpp plugin which is to be consumed by the qml application.
For this, I have created two projects. One is for creating a plugin library and another application is for consuming the plugin.
I am able to create the plugin library successfully. But, not able to consume it by the test application.
The test application is compiled successfully but throwing below error during run time.
QQmlApplicationEngine failed to load component
qrc:/main.qml:3:1: module "MyPlugin" is not installed
I have read the Qt documentation and googled a lot, but could not able to resolve it.
Qt : 5.15.7
Qt Creator: 5.0.3
OS: Ubuntu 18.04
Project 1: Creating Plugin library
CreatePlugin.pro
TEMPLATE = lib
TARGET = CreatePlugin
QT += qml quick
CONFIG += plugin c++11
DESTDIR = ../pluginFiles
TARGET = $$qtLibraryTarget($$TARGET)
uri = MyPlugin
# Input
SOURCES += \
createplugin_plugin.cpp \
myplugin.cpp
HEADERS += \
createplugin_plugin.h \
myplugin.h
DISTFILES = qmldir
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
copy_qmldir.target = $$OUT_PWD/qmldir
copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
copy_qmldir.commands = $(COPY_FILE) "$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)"
"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)"
QMAKE_EXTRA_TARGETS += copy_qmldir
PRE_TARGETDEPS += $$copy_qmldir.target
}
qmldir.files = qmldir
unix {
installPath = $$[QT_INSTALL_QML]/$$replace(uri, \., /)
qmldir.path = $$installPath
target.path = $$installPath
INSTALLS += target qmldir
}
# Copy the qmldir file to the same folder as the plugin binary
cpqmldir.files = qmldir
cpqmldir.path = $$DESTDIR
COPIES += cpqmldir
createplugin_plugin.h
#ifndef CREATEPLUGIN_PLUGIN_H
#define CREATEPLUGIN_PLUGIN_H
#include <QQmlExtensionPlugin>
class CreatePluginPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri) override;
};
#endif // CREATEPLUGIN_PLUGIN_H
createplugin_plugin.cpp
#include "createplugin_plugin.h"
#include "myplugin.h"
#include <qqml.h>
void CreatePluginPlugin::registerTypes(const char *uri)
{
// #uri MyPlugin
qmlRegisterType<MyPlugin>(uri, 1, 0, "MyPlugin");
}
myplugin.h
#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include <QObject>
#include <QString>
class MyPlugin : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(MyPlugin)
public:
explicit MyPlugin(QObject *parent = nullptr);
~MyPlugin() override;
public slots:
QString getString();
};
#endif // MYPLUGIN_H
myplugin.cpp
#include "myplugin.h"
MyPlugin::MyPlugin(QObject *parent)
: QObject(parent)
{
// By default, QQuickItem does not draw anything. If you subclass
// QQuickItem to create a visual item, you will need to uncomment the
// following line and re-implement updatePaintNode()
// setFlag(ItemHasContents, true);
}
MyPlugin::~MyPlugin()
{
}
QString MyPlugin::getString()
{
return "This is CPP String";
}
qmldir
module MyPlugin
plugin CreatePlugin
Project 2: TestPlugin
TestPlugin.pro
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
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
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();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import MyPlugin 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
MyPlugin {
id: mypluginId
}
Component.onCompleted: console.log(mypluginId.getString())
}

How to use QML Loader when the loaded component references another internal component

I have a repo at https://github.com/jh3010-qt-questions/qml_location/tree/loader_with_another_component
I am using Loader to load the MyDeeperComponent into main.qml's Column. However, MyDeeperComponent references another internal component called MySquare. When it loads, I get the error MySquare is not a type and the program quits. Of course, if I comment out MySquare from MyDeeperComponentForm.ui.qml, everything works and MyDeeperComponent loads successfully.
What needs to be changed so MyDeeperComponent can use MySquare and be dynamically loaded?
The directory structure is:
$ tree qml_location/
qml_location/
├── MySquare.qml
├── MySquareForm.ui.qml
├── main.cpp
├── main.qml
├── qml
│   └── more
│   ├── MyDeeperComponent.qml
│   └── MyDeeperComponentForm.ui.qml
├── qml.qrc
├── qml_location.pro
└── qml_location.pro.user
qml_location.pro
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 = $$PWD/qml
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH = $$PWD/qml
# 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>qml/more/MyDeeperComponent.qml</file>
<file>qml/more/MyDeeperComponentForm.ui.qml</file>
<file>MySquare.qml</file>
<file>MySquareForm.ui.qml</file>
</qresource>
</RCC>
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window
{
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column
{
MySquare {}
Loader {
source: "qrc:/qml/more/MyDeeperComponent.qml"
}
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.addImportPath( "qrc:/qml" );
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();
}
MySquare.qml
import QtQuick 2.4
MySquareForm {
}
MySquareForm.ui.qml
import QtQuick 2.4
Rectangle {
width: 40
height: 40
color: "blue"
}
Alternatively edit MyDeeperComponentForm.ui.qml by changing
MySquare {}
to
Loader {
source: "../../MySquare.qml"
}
or by adding (as already mentioned in the comments)
import "../.."
Note however, that your use case looks pretty weird from the dependency point of view... I suppose you are already familiar with different import mechanisms in QML but adding the link anyway for reference.

How can I organize QML files into nested folders?

I have a sample project at https://github.com/jh3010-qt-questions/qml_location
If my hierarchy looks like:
$ tree qml_location/
qml_location/
├── MyDeepComponent.qml
├── MyDeepComponentForm.ui.qml
├── main.cpp
├── main.qml
├── qml.qrc
└── qml_location.pro
Then I can write main.qml like:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
MyDeepComponent {}
}
and it will work.
However, I would like to organize some QML files into a folder hierarchy and not have them all at the same level.
For example, if I move to:
$ tree qml_location/
qml_location/
├── main.cpp
├── main.qml
├── qml
│   ├── MyDeepComponent.qml
│   ├── MyDeepComponentForm.ui.qml
│   └── more
│   ├── MyDeeperComponent.qml
│   └── MyDeeperComponentForm.ui.qml
├── qml.qrc
└── qml_location.pro
and have a main.qml that looks like:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window
{
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column
{
MyDeepComponent {}
MyDeeperComponent {}
}
}
Qt Creator tells me that MyDeepComponent and MyDeeperComponent are Unknown.
When I try to run, I get the error: MyDeepComponent is not a type
What can I do so this will work?
One caveat, I do not want to place a special or additional import at the top of main.qml. Is this still possible?
qml.qrc
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>qml/MyDeepComponent.qml</file>
<file>qml/MyDeepComponentForm.ui.qml</file>
<file>qml/more/MyDeeperComponent.qml</file>
<file>qml/more/MyDeeperComponentForm.ui.qml</file>
</qresource>
</RCC>
qml_location.pro
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
This answer doesn't meet the requirement of no imports, but it is worth mentioning anyway that it can be solved with a couple of imports at the top of main.qml.
https://github.com/jh3010-qt-questions/qml_location/tree/import_solution
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import "qml"
import "qml/more"
Window
{
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column
{
MyDeepComponent
{
}
MyDeeperComponent
{
}
}
}
You can do something like this:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window
{
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column
{
Loader {
source: "qrc:/qml/MyDeepComponent.qml"
}
Loader {
source: "qrc:/qml/more/MyDeeperComponent.qml"
}
}
}
Though I'm not quite sure why you would want to. Might help to describe the problem you are trying to solve?
https://github.com/jh3010-qt-questions/qml_location/tree/create_object_solution
createObject can be used to load the component directly into the Column.
main.qml looks like:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window
{
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property var componentNames: [ "qml/more/MyDeeperComponent.qml", "qml/MyDeepComponent.qml" ]
function generateObjects()
{
function generateOneObject( name )
{
var component
var componentObject
function finishCreation()
{
componentObject = component.createObject( contentColumn );
}
component = Qt.createComponent( `qrc:/${name}` )
if ( component.status === Component.Ready )
{
finishCreation()
}
else
{
component.statusChanged.connect( finishCreation );
}
}
for ( var index in componentNames )
{
generateOneObject( componentNames[ index ] )
}
}
Component.onCompleted: {
generateObjects()
}
Column
{
id: contentColumn
}
}
Another solution is to move main.qml into the qml folder. This allows main.qml to find MyDeepComponent because they are siblings. To find MyDeeperComponent, main.qml can import the "more" directory.
This solution in represented in the all_in_one_solution branch.
directory structure
$ tree qml_location/
qml_location/
├── main.cpp
├── qml
│   ├── MyDeepComponent.qml
│   ├── MyDeepComponentForm.ui.qml
│   ├── main.qml
│   └── more
│   ├── MyDeeperComponent.qml
│   └── MyDeeperComponentForm.ui.qml
├── qml.qrc
├── qml_location.pro
└── qml_location.pro.user
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/qml/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.qrc
<RCC>
<qresource prefix="/">
<file>qml/main.qml</file>
<file>qml/MyDeepComponent.qml</file>
<file>qml/MyDeepComponentForm.ui.qml</file>
<file>qml/more/MyDeeperComponent.qml</file>
<file>qml/more/MyDeeperComponentForm.ui.qml</file>
</qresource>
</RCC>
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import "more"
Window
{
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column
{
MyDeepComponent
{
}
MyDeeperComponent
{
}
}
}
EDIT: I'm reading your part of the question where you state that you don't want an import at the top. I don't think this is possible, without throwing a bunch of addImportPath in your main (for each folder that you are to create) or heavy fiddling with qrc-aliases. Leaving the rest of the answer for a future visitor or for if you change your mind ;-)
You can use a qmldir file to make them available in a namespace of choice. But there is a bit of a learning curve. The qmldir file has to be situated in folder which resembles the namespace.
For example if you want to use MyApplication as namespace, you have to put the qmldir file in a folder "MyApplication" (within the qml import path). If you want MyOrg.application1 as namespace, you have to put qmldir in "MyOrg/application1".
For your situation, I choose the first option. I would make a separate qrc file for the importable qml files, which is also needed if you want to easily put all qml files in a "qml" folder:
qml/qml.qrc:
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/qml/MyApplication">
<file>MyDeepComponent.qml</file>
<file>MyDeepComponentForm.ui.qml</file>
<file>more/MyDeeperComponent.qml</file>
<file>more/MyDeeperComponentForm.ui.qml</file>
<file>qmldir</file>
</qresource>
</RCC>
A simple qmldir would look something like this:
module MyApplication
MyDeepComponent 1.0 MyDeepComponent.qml
MyDeeperComponent 1.0 more/MyDeeperComponent.qml
You can see that I used a prefix, such that the files don't have to move. If you are to go to great heights with the app and want a MyApplication 2.0 namespace, you can use the prefix /qml/MyApplication.2

View PDF in QML WebView

I would like to view a PDF file in a WebView created in my QML code. I am importing QtWebView 1.1 and setting the url property to the path of the PDF file but I am getting this error:
[13044:12820:0314/144814.854:ERROR:in_progress_cache_impl.cc(192)]
Cache is not initialized, cannot RetrieveEntry.
[13044:12820:0314/144814.854:ERROR:in_progress_cache_impl.cc(176)]
Cache is not initialized, cannot AddOrReplaceEntry.
[13044:12820:0314/144814.854:ERROR:in_progress_cache_impl.cc(192)]
Cache is not initialized, cannot RetrieveEntry.
When I use the same code to view an image it works. This question: Display PDF file with QWebView is close to what I want but QML does not seem to give me access to the settings method the way that C++ does (WebView docs). Is there some other way to do this?
It seems that you are confusing elements, QWebView belongs to QtWebkit (uses Webkit) that no longer exists in Qt and that was replaced by Qt WebEngine (uses chromium). And another thing is WebView of Qt WebView that uses the native APIs (for example Android does not support Qt WebEngine but if WebView).
Qt WebEngine and Qt WebView does not support PDF visualization (Qt WenEngine will support it very soon) natively so a solution is to use some js library that does it as PDF.js so that is the alternative that I propose in base to an old answer.
*.pro
QT += quick webview
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += qml.qrc
COPY_CONFIG = 3rdParty example.pdf
copy_cmd.input = COPY_CONFIG
copy_cmd.output = ${QMAKE_FILE_IN_BASE}${QMAKE_FILE_EXT}
copy_cmd.commands = $$QMAKE_COPY_DIR ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
copy_cmd.CONFIG += no_link_no_clean
copy_cmd.variable_out = PRE_TARGETDEPS
QMAKE_EXTRA_COMPILERS += copy_cmd
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtWebView>
class PDFJS: public QObject
{
Q_OBJECT
Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
QString m_version;
public:
QString version() const{
return m_version;
}
void setVersion(QString version){
if (m_version == version)
return;
m_version = version;
Q_EMIT versionChanged(m_version);
}
Q_SIGNAL void versionChanged(QString version);
Q_INVOKABLE QUrl getUrl(const QUrl & path){
QString pdfjs_path = QDir::current().filePath(QString("3rdParty/pdfjs-%1-dist/web/viewer.html").arg(m_version));
QUrl pdf_url = QUrl::fromLocalFile(pdfjs_path);
QUrlQuery query;
query.addQueryItem("file", path.toString());
pdf_url.setQuery(query);
return pdf_url;
}
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QtWebView::initialize();
QQmlApplicationEngine engine;
PDFJS pdfjs;
engine.rootContext()->setContextProperty("applicationDirPath", QGuiApplication::applicationDirPath());
engine.rootContext()->setContextProperty("PDFJS", &pdfjs);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtWebView 1.1
Window {
visible: true
width: 640
height: 480
title: qsTr("PDFJS Example")
WebView{
id: webview
anchors.fill: parent
}
Component.onCompleted:{
PDFJS.version = "2.1.266"
webview.url = PDFJS.getUrl("file://" + applicationDirPath + "/example.pdf")
}
}
You can find the complete project here
Update: only QML
.
|-- 3rdParty
| `-- pdfjs-2.1.266-dist
|-- example.pdf
`-- main.qml
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtWebView 1.1
Window {
visible: true
width: 640
height: 480
title: qsTr("PDFJS Example")
WebView{
id: webview
anchors.fill: parent
}
Component.onCompleted:{
var pdfjs_path = Qt.resolvedUrl("3rdParty/pdfjs-2.1.266-dist/web/viewer.html")
var path = Qt.resolvedUrl("example.pdf");
var url = pdfjs_path + "?file=%1".arg(path)
console.log(url)
webview.url = url
}
}
This part of the project you find here
Another option to this problem is to look into the Poppler Library. This library can be used to convert a page in a PDF to an image. Take a look into the Poppler::Page object's renderToImage. The image can then be displayed on a QQuickPaintedItem. Hope this helps someone.

Using QtCreator 5.3 for Qt Quick UI project, how to link QML button resource to C++ function call

This is my first post on StackOverflow so please excuse any formatting mistakes I might have made.
I'm building a Qt Quick UI project using Qt Quick Controls 1.1 and I have a simple Button in my QML code that I would like to call into my C++ action class. I see a number of examples on this with earlier versions of Qt, but they do not seem to work in 5.3. I chose Qt Quick Controls 1.1 in the project settings. I know this must not be too complicated to do, but I can't seem to find examples using QtCreator 5.3
Here is my main.qml file:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
ApplicationWindow {
id: parentWnd
visible: true
width: 640
height: 480
Action {
id: actionSend
onTriggered: console.log("SEND")
}
Button {
id: send
text: "Send Request"
action: actionSend
signal sendSignal()
}
}
Here is my main.cpp:
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
Here is the action class where I would like the QML button to call "doSend":
#include<QDebug>
#include<QObject>
class Action : public QObject
{
Q_OBJECT
public:
Action();
public slots:
void doSend();
};
Finally here is my project file:
TEMPLATE = app
QT += qml quick widgets
SOURCES += main.cpp \
action.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)
HEADERS += \
action.h
When I run this, I see the button and I see the logging of "SEND" to the console so I know the QML Action is setup correctly. Any help on how to make the Action call into my action class would be much appreciated!
There are three issues that you're running into here.
The first is that you haven't registered your Action class with QML in main.cpp:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlRegisterType<Action>("StevesModule", 1, 0, "Action");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
The second is that Action is a QML type in the Qt Quick Controls module. It doesn't know anything about your Action class in C++. If you want to use your Action class instead of Qt Quick Controls' Action type, you must import it in your QML file:
import StevesModule 1.0
The third is that you're not calling the doSend() slot anywhere. You can do this in the onClicked handler of Button:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import StevesModule 1.0
ApplicationWindow {
id: parentWnd
visible: true
width: 640
height: 480
Action {
id: actionSend
}
Button {
id: send
text: "Send Request"
onClicked: actionSend.doSend()
}
}

Resources