Qt Quick Designer plug-in
-
I need to create new property type known by Qt Quick Designer, the properties of that types needs to be set from a drop down list, the content of the list is loaded from file specified in .pro. It seems that I need to create a plug-in that will make Qt Quick Designer aware of the new type and do this special thing as it does for e.g. QColor.
Can anyone help with this? I was looking for documentation in the network for Qt Quick Designer plug-in but can’t find anything, there is only documentation for Qt Designer plug-ins but this is not the same...
thanks
-
We do not support writing these plugins officially (for now) and the format might change in the future. Still writing such a plugin and the desktopplugin is a good example.
It can be found in creator/src/plugins/qmldesigner/desktopplugin
A plugin provides an xml file (desktopplugin.metainfo) and the icons.
The xml file and icons should be resources of the plugin and QString metaInfo() const; returns the path to the xml file ( return QString(":/desktopplugin/desktop.metainfo"); ).An entry for an item library in the xml file looks like this:
@ <node name="Label" icon=":/desktopplugin/images/label16.png">
<itemlibraryentry name="Label" category="Components Desktop" libraryIcon=":/desktopplugin/images/label.png" version="1.0" requiredImport="com.desktop">
<property name="text" type="QString" value="Label"/>
</itemlibraryentry>
</node>@The entry requiredImport means that the entry is only visible if the current document has the import com.desktop.
With property default values can be defined.
With icon a small icon for the navigator is specified and libraryIcon icon specifies a big icon for the library.
A single component like Slider can have more then one itemlibraryentry. This is useful for having a vertical and horizontal slider and defining different default values. -
Thanks for the responce.
I think, this explains how to add a plugin that adds QML Components to QML Designer library, I will need that too but I still wonder how to add new property type that would be set from a drop down list, here I need to add something to property editor, right?
-
This is a bit more complicated. ;)
You could register a new type of Widget to QML in your plugin. The property editor "sheets" are written in QML an can use the widget then.
The QML code for the existing property sheets can be found here:
creator\share\qtcreator\qmldesigner\propertyeditor
-
is it possible to add a context menu plugin instead? This would work for me as well. I have found an example how to do this in Qt Designer ("link":http://doc-snapshot.qt-project.org/4.8/designer-creating-custom-widgets-extensions.html) but can this be done in Qt Quick Designer?
-
Do you want to add edit functionality for a new property to any Item or just a new one?
The first would be impossible, but the second is possible by adding a new sheet in QML for the new Item and providing a custom widget as a plugin.
The connection would be that you use a new specific widget in the sheet that you register to QML in your plugin.
The plugin has to be build source compatible to the Qt Creator release which is possible.The concept of a menu plugin instead does not exist, yet. There is of course the possibility to contribute a nice interface to Qt Creator/Qt Quick Designer via Qt Project.
In an ideal world there would exist interfaces for extending context menus, delegates in the form editor and of course customizing the property editor (which is already possible but there are known issues limits. For example we currently do not export the classes for accessing the internal model. We could do this but this would mean longer loading times for everybody.).
All of this comes with a definite maintenance burden and atm we just do not have the resources.
Currently we focus on Qt Quick 2.0/Qt5 support.
Contributions are of course welcome.
-
I have made some progress but stuck now.
I have created sample project Qt Quick Application, and my new type for properties:
@
class MyType : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(string name READ getName WRITE setName)public:
MyType(QDeclarativeItem *parent = 0) : QDeclarativeItem(parent) { }string getName() const { return m_name; } void setName(const string &name) { m_name = name; }
private:
string m_name;
};
@and registered it in main()
@
qmlRegisterType<MyType>("MyUri", 1, 0, "myType");
@I have found a place in QmlDesigner plugin for Qt Creator where it generates templates for properties types and added there my template, reusing available ComboBox component: templateGeneration() src\plugins\qmldesigner\components\propertyeditor\propertyeditor.cpp:
@
if (typeName == "myType") {
qmlTemplate += QString(QLatin1String(
"QWidget {\nlayout: HorizontalLayout {\nLabel {\ntext: "%1"\ntoolTip: "%1"\n}\nComboBox {\nbackendValue: backendValues.%2\nbaseStateFlag: isBaseState\nitems : { ["test value 1", "test value 2"] }\n}\n}\n}\n"
)).arg(name).arg(properName);
emptyTemplate = false;
}
@And it works, when I create a QML Component that has a property of this type:
@
import QtQuick 1.1
import MyUri 1.0Rectangle
{
property myType myVariable: myType {
name: ""
}
width: 59
height: 36
}
@And use it in a different component:
@
TestComponent
{width: 71 height: 68 radius: 1
}
@I see a nice combo box in property editor displaying my two hard coded values.
But I do not know how to make the QmlDesigner to put selected value from combo box into the name property of myType.
@
TestComponent
{width: 71 height: 68 radius: 1 myVariable: myType { name: "test value 1" <---------------------------- }
}
@I know that the value assignment is in changeValue() src\plugins\qmldesigner\components\propertyeditor\propertyeditor.cpp:~450
@
if (castedValue.isValid() && !castedValue.isNull()) {
m_locked = true;
fxObjectNode.setVariantProperty(propertyName, castedValue);
m_locked = false;
}
@but castedValue.isNull() is true and nothing happens.
Any idea where to go now?
-
What you are trying to do is quite sophisticated.
Means that we did not anticipate people would try this ;)qmlRegisterType<MyType>("MyUri", 1, 0, "myType");
This registers your type in the code model, so we know about it. This is not sufficient to render your component (Which is not your question). If you also want to see your component in the Designer you have to make it a plugin and install it in the imports directory like the official plug-ins coming with Qt.
What you do is creating a generic ComboBox for your custom item. But the generic ComoBox does not know how to handle a property of type MyType.
What we did for cases like this (e.g. Gradient) is writing custom controls in C++ and expose those to .qml. You would have to create: MyTypeCustomControl and expose it like our Gradient editing.
Actually we are revisiting extending the property editor and hopefully it will be a lot easier in the future.
One Idea would be to automatically expose myVariable in the property editor as a subsection.
Then the user would get a "mini" property editor for MyType inside the property editor for TestComponent.One immediate problem I see is that a property like myVariable is super flexible.
In practice one could even subclass from MyType and assign the subclass. This is properly even a use case. And then it gets too complicated in the ui.
We have to find the line between usefulness and complexity.For now I would suggest creating property aliases in TestComponent for all the relevant properties of
MyType.We definitely have to find a solution for types like font.
But even now you can write a custom control in C++ put it in a QtQuick Designer Plugin and register it as qmlRegisterType<T>("Bauhaus",1,0,"T");
Then it is available in the property editor.
And we probably should make templateGeneration() expendable (without patching).
Already you could write a property pane for TestComponent by hand (.qml). This is also an area we will clean up, polish and then document.
-
Just to clarify, I do not want to write property pane for TestComponent or any other componet. I want to have my new custom, special type (myType) for properties that can be used in many QML components.
The MyType is complex, it will have more that one property, and I want them to be filled in automatically based on single user action - selecting one value from ComboBox - one selection results in setting complex property to value. I imagine that QMLDesigner create an instance of myType, assign it to myVariable property and generates this:
@
myVariable: myType {
name: "test value 1"
}
@I will try to check the Gradient.
But the starndard ComboBox.qml has something like this
@
QComboBox {
id: box
property variant backendValue: comboBox.backendValue
onCurrentTextChanged: { backendValue.value = currentText; evaluate(); }
@here a value from QComboBox is assigned to backendValue.value on change. I would expect that I get this value as castedValue in changeValue() src\plugins\qmldesigner\components\propertyeditor\propertyeditor.cpp:~450. The castedValue is even QString which is what I expected by why it is empty? I must be missing something...
At the end I will probably create MyComboBox.qml that will do more - load items dinamically based on project configuration. But at this point I wanted to figure out how all this value passing from property editor to QML file works.
By the way, how to add custom entries to .qmlproject and access it from propertyeditor.cpp or QML?
-
ComboBox is written for enums.
I understand what you want to achieve. Right now the only way is to write the special ComboBox you need in C++ and expose this like the gradient editor for example.
-
Did you find a solution? I've an analog problem with a string property named sscName that I want to be set using a combobox. I found a dirty trick that works in my situation (the property name is known) but I'd like to find a clean approach to the problem.
My dirty solution it was to modify :
share/qtcreator/qmldesigner/propertyeditor/PropertyTemplates/StringEditorTemplate.templateQWidget {
layout: HorizontalLayout {
Label {
text: "%1"
toolTip: "%1"
}
LineEdit {
backendValue: backendValues.%2
baseStateFlag: isBaseStateComponent.onCompleted : { if (backendValues.%2.name != "sscName") visible = true; else visible = false; } }
ComboBox {
baseStateFlag: isBaseState
minimumHeight: 22;
items : { ["Pompa", "Elica", "Porta"] }
backendValue : backendValues.%2Component.onCompleted : { if (backendValues.%2.name == "sscName") visible = true; else visible = false; } currentText: backendValues.%2.value; onItemsChanged: { currentText = backendValues.%2.value; } } }
}
A cleaner approach I attempted it was to define a new custom type
for SscName:Item
{
default property string value;
}(for testing purpose defined directly inside the project)
to add a new property template called SscNameEditorTemplate.template:
QWidget {
layout: HorizontalLayout {
Label {
text: "%1"
toolTip: "%1"
}ComboBox
{
baseStateFlag: isBaseState
minimumHeight: 22;
items : { ["Pompa", "Elica", "Porta", "Ciccio"] }
backendValue : backendValues.%2currentText: backendValues.%2.value; onItemsChanged: { currentText = backendValues.%2.value; }
}
}
}
But as happens to spaluc, backendValues.%2.value is not valid while the editor setup the property editor. If Iive understood a c++ plugin to implement the type SscName is needed. Any suggestion on how to implement it and on where tu put the library to be loaded by qt creator?