Qt Quick 2 Extension Plugin



  • Bin ein absoluter Neuling was Qt betrifft und habe Probleme, einen C++ Plugin zu erzeugen/installieren. Ich benutze Qt 5.0.0 mit Creator 2.6.1 und MSVC2010 als Compiler, Win7/64, i5, GFORCE GTX650Ti, 8GB RAM... Alle Treiber sollten aktuell sein.

    Qt Quick ist eine sehr intuitive Markup Language und mir gefällt die Verbindung zw. Qt Quick und C++. Leider muss ich nach langem Probieren mir hier Hilfe suchen, da ich den Testplugin leider nicht installiert bekomme. Ich habe mir verschiedene Tutorials und Beispiele angesehen, ohne Erfolg. Ich hoffe, jemand macht sich die Mühe, über den nachfolgenden Code zu schauen und kann mir ein paar wertvolle Tips geben.

    Was habe ich getan?!

    Als erstes habe ich einen Plugin mit Hilfe des Qt Quick 2 Extension Plugin Wizards angelegt. Über Sinn und Zweck dieses Plugins müssen wir uns, glaube ich, nicht unterhalten.

    Projektdatei: firsttest.pro

    @TEMPLATE = lib
    TARGET = firsttest
    QT += qml quick
    CONFIG += qt plugin

    DESTDIR = $$[QT_INSTALL_IMPORTS]/firsttest

    TARGET = $$qtLibraryTarget($$TARGET)
    uri = firsttest

    SOURCES +=
    firsttest_plugin.cpp
    firsttest.cpp

    HEADERS +=
    firsttest_plugin.h
    firsttest.h

    OTHER_FILES = 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_IMPORTS]/$$replace(uri, \., /)
    qmldir.path = $$installPath
    target.path = $$installPath
    INSTALLS += target qmldir
    }
    @

    Header: firsttest.h
    @#ifndef FIRSTTEST_H
    #define FIRSTTEST_H
    #include <QQuickItem>

    class FirstTest : public QQuickItem
    {
    Q_OBJECT
    Q_DISABLE_COPY(FirstTest)

      QString String1;
      QString String2;
    
      Q_PROPERTY(QString string1 READ string1 WRITE setString1 NOTIFY string1Changed)
      Q_PROPERTY(QString string2 READ string2 WRITE setString2 NOTIFY string2Changed)
      Q_PROPERTY(QString addStrings READ addStrings)
    

    public:
    FirstTest(QQuickItem *parent = 0);
    ~FirstTest();

      void setString1(QString);
      void setString2(QString);
      QString string1();
      QString string2();
      QString addStrings();
    
      Q_SIGNALS:
          void string1Changed(bool);
          void string2Changed(bool);
    

    };

    QML_DECLARE_TYPE(FirstTest)
    #endif // FirstTest_H
    @

    Header: firsttest_plugin.h
    @#ifndef FIRSTTEST_PLUGIN_H
    #define FIRSTTEST_PLUGIN_H
    #include <QQmlExtensionPlugin>

    class FirsttestPlugin : public QQmlExtensionPlugin
    {
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")

    public:
    void registerTypes(const char *uri);
    };

    #endif // FIRSTTEST_PLUGIN_H@

    Source: firsttest.cpp
    @#include "firsttest.h"

    FirstTest::FirstTest(QQuickItem *parent): QQuickItem(parent)
    {
    String1 = "\0";
    String2 = "\0";
    }

    FirstTest::~FirstTest() {}

    void FirstTest::setString1(const QString string)
    {
    String1 = string;
    emit string1Changed(true);
    }

    void FirstTest::setString2(QString string)
    {
    String2 = string;
    emit string2Changed(true);
    }

    QString FirstTest::string1()
    {
    return(String1);
    }

    QString FirstTest::string2()
    {
    return(String2);
    }

    QString FirstTest::addStrings()
    {
    return(String1 + " " + String2);
    }@

    Source: firsttest_plugin.cpp
    @#include "firsttest_plugin.h"
    #include "firsttest.h"
    #include <qqml.h>

    void FirsttestPlugin::registerTypes(const char *uri)
    {
    qmlRegisterType<FirstTest>(uri, 1, 0, "FirstTest");
    }@

    qmldir-file:
    @module firsttest
    plugin firsttest
    @

    Anschließend habe ich alles erstellt und die Dateien firsttest.dll, firsttestd.dll, die dazugehörigen .lib-Dateien und einige andere wurden unter C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports\firsttest angelegt. qmldir habe ich in das gleiche Verzeichnis kopiert. Habe dann ich eine Qt Quick Anwendung erzeugt und versucht, den Plugin einzubinden.

    Projektdatei: test.pro
    @folder_01.source = qml/Test
    folder_01.target = qml
    DEPLOYMENTFOLDERS = folder_01
    QML_IMPORT_PATH =
    SOURCES += main.cpp
    include(qtquick2applicationviewer/qtquick2applicationviewer.pri)
    qtcAddDeployment()@

    Source: main.cpp
    @#include <QtGui/QGuiApplication>
    #include "qtquick2applicationviewer.h"

    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);
    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/Test/main.qml"));
    viewer.showExpanded();
    return app.exec();
    }@

    Qml-File: main.qml
    @import QtQuick 2.0
    import firsttest 1.0

    Rectangle
    {
    width: 360
    height: 360

    FirstTest
    {
        id: test
        string1: "Hallo"
        string2: "World"
    }
    
    Text
    {
        text: test.addStrings
        anchors.fill: parent
    }
    

    }@

    Bewege ich die Maus über den import-Befehl, bekomme ich die Meldung "Bibliothek bei C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports\firsttest , Plugin-Informationen erfolgreich bestimmt."
    Leider kann ich auf die Elemente nicht zugreifen und ich bekomme beim Ausführen die Fehlermeldung, dass das Modul nicht installiert wurde.

    Ich habe auch versucht, den Plugin im Qml-Projektverzeichnis anzulegen, eine andere uri zu benutzen und diese über QML_IMPORT_PATH = ... bzw. QML2_IMPORT_PATH = ... einzubinden, eine andere IID für das Macro Q_PLUGIN_METADATA zu benutzen, der Bibliothek einen anderen Namen als den Klassennamen zu geben, usw., leider immer mit dem selben Ergenis.

    Über schnelle Hilfe wäre ich sehr dankbar, da ich keine Ideen mehr habe.



  • First of all you need to ensure that your plugin is installed correctly.
    QtCreator will use this plugin for auto-complition, and syntax validation during development.

    you just have to copy *.so, qmldir and plugins.qmltypes it the location C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports\firsttest

    if your plugin is named "com.example.firsttest", than you have to create the entire directory tree
    C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports\com\example\firsttest

    this should fix your issue. it worked for me.



  • Thank you for your response,

    my plugin is named "firsttest". I build the .dll, ..d.dll files and the plugins.qmltypes at C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports\firsttest. (DESTDIR = $$[QT_INSTALL_IMPORTS]/firsttest) Then I copied qmldir to this location. After this I modified qmldir and inserted "typeinfo plugins.qmltypes".

    In the QtQuick2 projects main.qml file I imported the plugin with "import firsttest 1.0" If I hover with the mouse over the import command the creator shows that there is a library at the location C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports\firsttest and typeinfo file is read.

    Then I can bild the project. The execution stops with the message ""module "firsttest" is not installed "" import firsttest 1.0

    Now I changed the directory and the name of the plugin to "com.example.firsttest", made a new build at com.example.firsttest, copied qmldir to /imports/com/example/firsttest. In my main.qml file I changed the import command to "import com.example.firsttest 1.0" the creator finds the library but the execution fails with the same error message.

    I also tried to use different names for module, plugin and class but it makes no difference.

    I dont know, what I can do anymore.

    regards,
    andré



  • in your main.cpp file you can set the import path manualy
    viewer.engine()->setImportPath("location to your library");

    seems like the variable from *.pro is not taken into consideration.



  • I have no clue why QML_IMPORT_PATH does not work as expected, but at least there is a workaround



  • You can modify your main.cpp, like below, and should work.
    the method used is addImportPath, not setImportPath as I previously said

    @
    #include <QtGui/QGuiApplication>
    #include "qtquick2applicationviewer.h"

    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);
    QtQuick2ApplicationViewer viewer;
    viewer->engine()->addImportPath("<your_path>");
    viewer.setMainQmlFile(QStringLiteral("qml/Test/main.qml"));
    viewer.showExpanded();

    return app.exec();
    }@

    regards,
    Dănuț



  • hello dănuț,

    thanks for your effort. the code you posted is exatly the same i tried yesterday in the evening with the same result as before.
    today in the morning i tested the code on ubuntu with qt5 and gcc64. i thought it is a problem of the .dll but the result was also the same on linux with the .so file.
    now i think there must be somthing wrong with the plugin code or with qt5 itself.
    have you ever used qt5 with the "Qt Quick 2 Extension Plugin" wizard with a executable result? if so can you send me please your sources including the .pro files.

    an other question at the macro "Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")". im not sure what iid i have to use. can i use "org.qt-project.Qt.QQmlExtensionInterface"? the tutorial says i have to use a unique id. whitch rules i have to observe and what does it mean when i use "aaa.bbb.ccc.ddd"

    regards,
    andré



  • Hi,
    According with the documentation, the ID just have to be unique
    @Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDummyPlugin" FILE "mymetadata.json")@

    In my test I have left the IID as it was generated (org.qt-project.Qt.QQmlExtensionInterface).
    In my workarea I have created 2 projects
    QtQuick2ExtentionPlugin
    and
    QtQuick2Application

    QtQuick2ExtentionPlugin project was generated using wizard, and I felt it as it was generated entirely.
    QtQuick2Application project was also generated using wizard, and than I have modified
    main.qml
    @import QtQuick 2.0
    import com.mycompany.qmlcomponents 1.0

    Rectangle {
    width: 360
    height: 360
    Text {
    text: qsTr("Hello World")
    anchors.centerIn: parent
    }
    MouseArea {
    anchors.fill: parent
    onClicked: {
    Qt.quit();
    }
    }
    MyItem
    {

    }
    

    }@

    and mai.cpp
    @
    #include <QtGui/QGuiApplication>
    #include "qtquick2applicationviewer.h"
    #include <QQmlEngine>

    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);

    QtQuick2ApplicationViewer viewer;
    //location to your plugin
    viewer.engine()->addImportPath("/###/Qt5.0.0/5.0.0/gcc/imports");
    viewer.setMainQmlFile&#40;QStringLiteral("qml/QtQuick2Application/main.qml"&#41;);
    
    viewer.showExpanded();
    
    return app.exec();
    

    }@

    than I have created next directory tree
    Qt5.0.0/5.0.0/gcc/imports/com/mycompany/qmlcomponents
    and copy inside qmldir and libQtQuick2ExtensionPlugin.so which were created when QtQuick2ExtentionPlugin was build.

    When QtQuick2Application is build and run, everything works just right.



  • hello dănuț,

    thanks again. i uninstalled Qt installed it again and then I tried to create the two projects with the the wizard setup, created the dir tree, copied the files and created the typeinfofile. then i modified the main.cpp ... unfortunately the same result.

    can you tell me which creator you use? i use 2.6.1 rvv 8d02f18140 with Qt5 final
    have you changed something at the build environmet?
    which switches you use for qmake / make?

    many thanks



  • Hi andré,
    my environment is similar with what you have..
    Ubuntu 12.10 (x64)
    Qt Creator 2.6.1 with Qt5.0.0 final

    http://harmattan-dev.nokia.com/docs/platform-api-reference/xml/daily-docs/libqt4/qdeclarativemodules.html this was the first tutorial I have follow.

    bq. The import path, as returned by QDeclarativeEngine::importPathList(), defines the default locations to be searched by the QML engine for a matching module. By default, this list contains:

    • The directory of the current file
    • The location specified by QLibraryInfo::ImportsPath
    • Paths specified by the QML_IMPORT_PATH environment variable

    having in mind that the current folder is the first one in which it search for your plugin, you can try to create the same directory tree inside your QtQuickApplication (or better a symlink to "com" folder )
    (this solution works for me also)

    regards,
    dănuț



  • hello dănuț,

    very thanks for your efforts to help me. finaly i solved the problem.
    i included "qputenv("QML_IMPORT_TRACE", "1");" to see which paths are included. then i saw that there are only 3 paths are included regardless of which paths i try to include with addImportPath or QML_IMPORT_PATH.

    1. QQmlImportDatabase::addImportPath: "C:\Qt\Qt5.0.0\5.0.0\msvc2010\qml"
    2. QQmlImportDatabase::addImportPath: "../test1-build-Desktop_Qt_5_0_0_MSVC2010_32bit_SDK-Debug/release"
    3. QQmlImportDatabase::addImportPath: "../test1-build-Desktop_Qt_5_0_0_MSVC2010_32bit_SDK-Release/debug"

    "C:\Qt\Qt5.0.0\5.0.0\msvc2010\imports" is not included and the paths #2 and #3 are emty. if i build a release version the path to the application is ... 32bit_SDK-Release/relase and not 32bit_SDK-Release/debug. this paths is created indeed but emty and if i build the debug version it is similar. so the linker can never find the module under ../imports/com/mycompany/qmlcomponents or ...Debug/debug/com/mycompany/qmlcomponents.

    Now i created the tree com/mycompany/qmlcomponents at this "wrong" path and everything works just right.
    I dont know why i cant add a import path maybe i is an issue of the creator or i dont have the rights to change some files in the qt environment (but i started the creator as admin). i hope it works with the next version of the creator.

    thank you very much,
    andré


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.