Sample app demonstrating QML + C++ Plugin ?



  • Hi,

    Sorry for this noob question, but as I'm totally new to the Qt world, I'm lost...
    Here is what I'm trying to do and where I'm stuck :
    I want to design an application using QML for Symbian(/Meego) : quite easy, there's a Wizard in Qt Creator that create the project for me.
    It's quite easy to build the UI and the simple logic around it, so I haven't got too much problem here.

    Here is the nice part : I want to execute something I can only code with C++ (broadcast a message on the network...). I've seen it possible to create a "plugin" and expose it to QML. It appears to be exactly what I need, from my PoV.

    My silly question is : what files to I have to add to my QML project, and where do I have to store them in order to build my "plugin" ?
    Since I'm new, I don't clearly understand the role of *.pro files, qmldir, and so on...

    If someone can describe what can be the architecture of such a project, and what to modify in my files, it could greatly help me.

    Thanks

    David


  • Moderators

    "This":http://developer.qt.nokia.com/doc/qt-4.7/qdeclarativeextensionplugin.html should lighten your day ;) In general, I strongly recommend diving into Qt documentation - it's probably the best documented framework I've seen.



  • Thank you for this link. But... It's still not enough for me.
    As I said, I'm REALLY :) totally new to Qt (I'm coming from the Java world, and I have many things to learn here, clearly).

    Even if I can understand how it works (I mean the spirit behind this plugin notion), I'm "just" stuck with the simple (for you not for me) problem : where in a typical project build with the wizard, do I have to create these files (I've read I can create a kind of subfolder for plugins), how do I declare these files ? in the "main" *.pro file at the project root ? in another *.pro file ? any link other files to modify ?

    In the great Nokia Qt documentation (I agree : it seems to be a gold mine), they don't clearly explain where to create the "TimeModel" class, nor where to create the QExampleQmlPlugin file(s), which "project file" to modify...

    Here is my current project tree :

    @PROJ1 /
    PROJ1.pro
    qmlapplicationviewer/
    Headers/
    Sources/
    main.cpp
    QML/
    qml/PROJ1/
    main.qml
    ... (some other qml files I've created here => this part was easy :) )@

    If you can explain what I have to add and where in the particular tree, that would be really nice.

    David


  • Moderators

    Oh, sure.

    Before going for a plugin, you can (at least as far as I gather from your info) try a simpler way: exposing QObjects in QML. So, let's say you've got your essential Qt/C++ class:
    @
    class Broadcast : public QObject {
    // This will be the method you want to invoke:
    Q_INVOKABLE void broadcastMessage();
    }
    @

    In your main.cpp, add:
    @
    qmlRegisterType<Broadcast>("com.broadcast", 1, 0, "Broadcast")
    @

    From now on, you should be able to do this in your QML:
    @
    import com.broadcast 1.0 // IMPORTANT BIT :)

    ... // somewhere in your code
    Broadcast {
    id: broad
    Component.onCompleted: { // Or anywhere else, for example in a MouseArea, Timer etc.
    broad.broadcastMessage();
    console.log("Message has been broadcasted");
    }
    }
    @

    Of course, this is just a starter. I can elaborate and complicate if you need :) Another helpful doc: "LINK":http://developer.qt.nokia.com/doc/qt-4.7/qml-extending.html.


  • Moderators

    I can also add the info you requested about the QML plugin, but I'm not that fluent there: I am about to start creating one myself for one of my projects (well, two :) ). The subdir QMake is pretty easy stuff, and as far as I remember the code that the default Qt Creator wizard for QML creates, modifying your project would not be too complicated.

    It's your call, but it seems to me, that for now the path from my previous post will be OK for you.



  • I'm giving it a try, thank you for your help.
    If it works, I will stay with it. I don't need too complicated things right now :)



  • So... some weird errors in Qt Creator when compiling...

    here is my main.cpp :
    @#include <QtGui/QApplication>
    #include <QtGui/QMessageBox>
    #include <QtDeclarative>
    #include "qmlapplicationviewer.h"

    class Broadcast: public QObject
    {
    Q_OBJECT

    Q_INVOKABLE void showMessage()
    {
        QMessageBox::information(NULL, "Test", "Test!");
    }
    

    };

    Q_DECL_EXPORT int main(int argc, char *argv[])
    {
    QScopedPointer<QApplication> app(createApplication(argc, argv));
    QScopedPointer<QmlApplicationViewer> viewer(QmlApplicationViewer::create());

    qmlRegisterType<Broadcast>("com.broadcast", 1, 0, "Broadcast");
    
    viewer->setMainQmlFile&#40;QLatin1String("qml/MyFirstApp/main.qml"&#41;);
    viewer->showExpanded();
    
    return app->exec&#40;&#41;;
    

    }
    @

    And I've got some errors :
    [...] In function QDeclarativePrivate::QDeclarativeElement<Broadcast>::~QDeclarativeElement()': [...] error: undefined reference tovtable for Broadcast'
    [...] In function int qmlRegisterType<Broadcast>(char const*, int, int, char const*)': [...] error: undefined reference toBroadcast::staticMetaObject'

    I tried to start from a fresh new Symbian skeleton QML app, and still the same issue.

    If I comment the line qmlRegisterType[...], it compiles...

    Damned : I'm lost


  • Moderators

    Very probably you have to add:
    @
    public:
    @
    before showMessage(). This is because default state of methods and members of a class in C++ is private. This is how your class should look like:
    @
    class Broadcast: public QObject
    {
    Q_OBJECT

    public:
    Q_INVOKABLE void showMessage()
    {
    QMessageBox::information(NULL, "Test", "Test!");
    }

    };
    @


  • Moderators

    Also, I am not sure whether you can use QMessageBox on Symbian - I've never developed for this platform. You can substitute it with @qDebug() << "Test";@ for the purpose of testing. It prints the string onto console. But first, try making that method public, as this is likely to be the cause.



  • Hi,

    As strange (to me at least) as it seems, I wasn't able to make it work that way.

    But, I've found another way to make this work.

    My default project, which comes from the Qt Creator wizard (QML app for Symbian plateform) contains a pseudo sub project (That's how I call it but I'm sure there is a real name for it) called "qmlapplicationviewer" containing a *.pri file and some C++ source code.
    I've added my class in this sub project and modified my main.cpp like this :
    @#include <QtDeclarative/QDeclarativeContext>
    #include <QtDeclarative/QDeclarativeView>
    #include <QtGui/QApplication>
    #include "qmlapplicationviewer.h"
    #include "broadcaster.h"

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

    QDeclarativeView view;
    
    Broadcaster broadcaster;
    view.rootContext()->setContextProperty("broadcaster", &broadcaster);
    
    view.setSource(QUrl::fromLocalFile&#40;"qml/MyAppForSymbian/main.qml"&#41;);
    view.show();
    
    return app.exec();
    

    }@

    And guess what : it works ! I can call my function, pass a parameter... all that I need, at least for now.

    Let's code right now !

    Thanks for your help. If you understand why the first solution doesn't work...

    I'm sure I'll have many other questions, but right now I can continue developing (and learning C++ and Qt4).


  • Moderators

    I'm happy you managed to get it to work.

    Seems like you got rid of all that "qmlapplicationviewer" - so, you don't really need the wizard-generated code anymore. But, since it works for now, let it be there. It's certainly easier to learn on something that works.

    I don't know, why my code does not work for you, it may be that I've missed something trival, and can't spot it now. I use a similar construct and it works well.



  • Hey, delirii! I have most of the answer you wanted in your original query. I figured this out today because I needed it myself.

    I have a QML application that uses a C++ plugin. Using QtCreator, I created a subdirs project ("flashcards). Inside that, I created two subprojects. For the UI, I created a Qt Quick Application ("flashcards"). For the plugin, I created a Custom QML Extension Plugin ("textstream"). I gave the plugin the URI "com.talmagemedia".

    The tricky part is finding the plugin after deployment. When QtCreator deploys to my N9 and to the Qt Simulator, it puts the plugin (i.e. the library and qmldir) in /usr/lib/qt4/imports/<plugin URI>.

    At runtime, the the app can't find the plugin when I run it under the Qt Simulator. It finds the plugin easily on my N9.

    For running on my N9, I use this import statement in main.qml:

    @
    import com.talmagemedia 1.0
    @

    To run it on the Qt Simulator, I needs this instead:

    @
    import "../../../textstream"
    @

    I haven't discovered the way to make the app find the plugin on both platforms without changing the source code. I'll bet it's trivial.


  • Moderators

    Since it's Friday, it's time for some random-reply-that-may-work:

    use QRC. I don't know how to manage the first import that way, but maybe it will work.


Log in to reply
 

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