Solved extend Application by plugins
-
Hey everyone,
I wondered how it's possible to extend an application by (community made) plugins.
I am thinking here of two popular examples, I am really interested how they could work.- The Kde plasma widget/plasmoid system
As I am experimenting with Wayland desktop environments and I was curious on how one can provide an easy to use API for integrating qt quick applications (like a menu, taskbar, calendar ..) in the environment -> the panel.
My first try was simply just an custom draggable element, people can subclass from. But in the code of the panel, one would have to add the plugin. Obviously, this is not really independently. And I would wish to separate it more from the compositor.So I thought about a better solution and this might me kind of a PluginLoader. One can make his plugin (maybe with the help of attachted properties for example for the look in the panel ... there might be a default look, but if needed it can be overwritten ... this would avoid subclassing a template plugin?). Then the files of the widget must been install into the plugin directory. From there the Plugin Loader have to pick it up and integrate it into the desktop.
So I have some ideas how this could work, but not really a clue on how to implement it.
- The Atom plugin system
As probably most know the Atom Code Editor is highly customizable through plugins. Sometimes I even thing, it's nothing else then plugins. And from what I see it's possible to have plugins for everything ... language support, theme, new features, layout changing ....
How is this achieved? Seems really common for code Editors as we have often things like a "Marketplace" for example in eclipse.
In the Qt docs I have seen a class named QPluginLoader. But it seems that they are talking from other kind of plugins than I do. At least I could not really see how this can help me in any of these two cases.
I appreciate any help to this topic. It's actually something I wondered about since I started with Qt. I don't expect anyone here to provide a complete working solution. But some hints in the right direction would be really helpful.Thanks!
-
Hi @Leon_2001,
Indeed Qt has a powerful plugin system. E.g. QtCreator is fully plugin-based.
For start, you might want to look at the Plug&Paint example.
-
Thanks !
So they did mean the same with plugins than I do :)
I will study the example and try to integrate it. I will post as soon I everything works (and change then the problem to solved) or when I have some further questions.
-
Hi @Leon_2001,
just for completeness: the "real world" example QtCreator. But for learning, Plug&Paint is better :)
-
So I read a lot of articles about the plugin system, but I still have some questions.
Main Problem is that I try to create qml plugins for qml and not qt widgets plugins/c++ plugins for qml, which seems to work different.
According to http://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html I was able to create a custom Qml type from C++ and compile it to a library with the help of QQmlExtensionPlugin. Then I could import the plugin in a qml file and use the custom qml type.
But actually this is not really what I wanted to achieve.
My plugin should look something like this for example
src
Backend- CustomModel.h
- CustomModel.cpp
Frontend - Main.qml
So basically a qml File (maybe using other qml files like CustomButton.qml) extended by some c++ backend.
Let's say this is a Rectangle showing some Text from the CustomModel. And there might be other Plugins ... like a Triangle, Circle ...
My Main qml Application should be a Window displaying all detected plugins in for example a GridLayout -> so they probably need to be add dynamically to an Object Model.
-
How could I make a plugin/library out of a qml project? And not only from c++ as described in the linked tutorial
-
How could I detect all plugins available at runtime and add them to an ObjectModel? I think here could maybe QPluginLoader help? But I suppose this mainly depends on the solution of the first question.
Thanks for your help!
-
Tried a lot and find a solution, which seems to work, although it maybe can be improved.
QmlExtensionPlugin was in deed the right way to go:
http://doc.qt.io/qt-5/qtqml-qmlextensionplugins-example.htmlSome additions to the tutorial:
If you want to have a module called "Test" then you qmldir file has to be in a Test folder. In you mainApplication you add the Path to this TestFolder (not to the qmldir) to the ImportPath.
app src import Test libtest.so Test.qml qmldir main.cpp
If this is your folder structure, you would to in main.cpp
engine.addImportPath("Import");
your qmldir would look like this
module Test CustomType 1.0 Test.qml plugin test
You could import then Test 1.0 in your qml files and use CustomType.
Instead, you might want the software to detect plugins. So here is my solution to this, there are probably better ways to do this (for example if you want to display all plugins in a Grid or something like this and don't know, which plugins might be there or won't)
- You need to have a consisten plugin structure. For example, name your Qml Component always Main.qml and put it in the first Folder (with your qmldir)
-> if you don't want to lose the ability to instantiate the Elements in qml by importing the module (as you probably don't want them all to be named Main), you can leave you Test.qml file just as it is and create a wrapper for this called Main.qml
import QtQuick 2.10 Item { id: root property alias someProperty: test.someProperty .... Test { id: test anchors.fill: parent } }
- Suppose all your plugins are in a folder called import, you could list all Folders (=Plugin folder) in the import Directory, iterate over them and get all the filePaths of Main.qml
QDir pluginsDir {"Import"}; for(QString folderName : pluginsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { if(pluginsDir.exists(folderName)) { pluginsDir.cd(folderName); if(pluginsDir.exists("Main.qml")) { qDebug() << pluginsDir.absoluteFilePath("Main.qml"); } pluginsDir.cdUp(); } }
- Make all the FilePaths available to qml, for example by creating a custom C++ QStringList model and import it in qml. In qml you can use those strings to instantiate the Elements with JavaScript.
See: http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html
Unfortunately, you cannot add plugins at runtime. You will need to restart the application, so it searches again for all plugins. You could solve this by creating a daemon watching the plugin directory and sending signals if there is a change.
If you have another (better/simpler) solution than this, feel free to add it here.