I'm using a QJSEngine to make an application scriptable. I'd like the JavaScript side to be able to modify the user interface. My main issue right now is accessing the Qt API from JavaScript.
To create widgets, I added a createWidget() wrapper that uses QUILoader:
// JavaScript
var w = helpers.createWidget("QPushButton");
// C++
QJSValue helpers::createWidget(QString type)
{
QUILoader ld;
return engine.newQObject(ld.createWidget(type));
}
I've also registered all the enums from qt_getQtMetaObject(), which seems to take care of all the namespace-level enums from qnamespace.h. It doesn't look like it's part of the public API though.
Am I really supposed to this stuff manually or am I missing something? Isn't there a registerAllTheThings() function that creates a global Qt object through which the Qt API available?
If there isn't, then I have a problem. I can create QWidgets with a QUILoader, but I couldn't find a way of creating other objects, such as a QStandardItemModel. I thought all Qt classes would already be registered through qRegisterMetaType(), but they're not: QMetaType::type("QStandardItemModel") fails by returning UnknownType. Again, am I missing some initialization function call that registers everything?
I would recommend using a QQmlEngine instead of the QJSEngine.
Is is derived from QJSEngine so it can do the same things, in the same module so no extra dependencies.
It provides an easy way to register types for instantiation in QML, has a plugin loading mechanism (imports), etc.
I presented that as part of my talk at Qt World Summit 2015: https://www.youtube.com/watch?v=7LsKoVrb8C8
Related
I want to dynamically instantiate a QWidget and bind its "Pressed" event, either with a Qt signal or by overriding a function.
However I'm only allowed to create one new .cpp file.
I don't know how to override a C++ function dynamically, or how to change a virtual function into a Qt signal.
Is what is represented in the picture above achievable ?
The Widgets Tutorial of the Qt docs is a nice starting point.
Under Qt Widgets Examples you can find the Calculator Example, which should contain all of what you want to do.
Take the code, strip it down to what you need, use and try to understand it.
Or maybe have a look at the Getting Started section.
I am reading about prototype pattern by GoF book. Here is the text snippet
Configuring an application with classes dynamically: Some runtime
environments let you load classes into an application dynamically. The
prototype pattern is the key to exploiting such facilities in a
language like C++.
An application that wants to create instances of a dynamically loaded
classes won't be able to reference its constructor statically.
Instead, runtime environment creates an instance of each class
automatically when it's loaded, and registers with a prototype
manager. Then the application can ask the prototype manager for newly
loaded classes, classes that weren't ;omled with the program orginally
My questions on above
What does author mean by "An application that wants to create instances of a dynamically loaded classes won't be able to reference its constructor statically" ? For example if we use dynamic link library I can still create object using new so what does author mean by we won't be able to reference constructor statically?
Request to give an example how prototype pattern is used to exploit load classes application dynamically.
My 50 cents on this :
I believe the author is referring to situations where you don't have the class definitions in the symbols library, however you want to instantiate objects, and pass them to the library consumer functions (so you are the memory owner, the shared library is the consumer , but you don't have access to the concrete classes inside the library )
Example ( I will write one from the top of my head to underline a scenario where it would be useful then I will write another one that I actually bumped into)
Having a dynamic library TextEditorWidgets.dll and your main application , the TextEditorWidget exposes an abstract prototype TEWPrototype , and a factory method of getting certain prototypes according to let's say a string identifier.
Having the factory method exposed from the dll defined as :
TEWPrototype* TEWPrototype::getPrototypeFor(string identifier)
{
TEWPrototype* result;
if (identifier == "SomeWidget")
{
result = ConcreteSomeWidgetPrototype;
} else if ...
return result;
}
Inside your application you can use the following code :
{
vector<TEWPrototype*> allocatedWidgets;
...
TEWPrototype* SomeWidget = TEWPrototype::getPrototypeFor("SomeWidget").clone();// you are now the memory owner
allocatedWidgets.push_back(SomeWidget); // keep for deletion
TextEditorWidgetsHandle->doSomethingWithTheWidget(SomeWidget);// pass the instantiation to the consumer who knows the widget full definition
}
In the example above you have the following pros as the app develoer :
you will control what the dll allocates , when and how
you will control if the widgets get deleted or not through the lifetime of the application
The pros as the dll developer :
you will be able to add new Widgets while providing backwards functionality
you have the guarantee that nobody will use your internal widgets functionality outside the .dll
Practical example :
While working on a game , new entities were created by the game development team, and we needed a fast way to give the Designers the new objects for them to add into the game scene. We had our own in house editor, so we had control over the design tool.
The approach was to have the World Editor load .dlls , then expose in the editor menus what objects were loaded in the dlls. The editor didn't know what classes were inside the dlls, it only knew about them having a draw and a setPosition function (and some other things).
When the dll was loaded , inside the editor, the name of the object was added into an object prototype manager (basically we had a static function getAvailableObjects and after dll load, we would query that in order to get the strings).
When a Designer was choosing from a menu an object (let's say for example Crate), then a new instance of that object was created that was drawn inside the editor , and the designer could move it around.
The editor couldn't instantiate the object by itself because he knew nothing about the size of the object nor about his constructor. However we had pre-instantiated objects for each type, that were getting cloned each time the Artist chosed to create a "new" Crate.
The preinstantiated objects were also used in the preview .
When the development team released a new set of entities , we just provided the new dll to the Designers, and they would only need to "refresh" the editor an BOOM : magic happened : new objects in the menu .
As an alternative, an abstract factory can provide kind of the same functionality.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Consider the case of a simple GUI displaying the output of rather elaborate calculation.
Now I would like to write a nice, custom GUI using QML.
I would also like to write my background app in QT C++.
I'm sitting in front of the QT documentation and wonder
if I
1) should write a QML application and somehow embed my C++ classes in it
(which is absolutely possible) or if I
2) should write a C++ application
and somehow embed the QML GUI in it and modify QML properties from my classes
(which is again possible)
I already wrote everything in C++ using QT Widgets for the GUI. I only want to move the GUI to QML and keep the C++ classes even though I am willing to rewrite the interface to the GUI.
Possible anser:
The marked solution below suggested keeping the C++ classes and interface the GUI exclusively through SIGNALS and SLOTS. So basically I ended up with a main.cpp that instantiates my main working class and displays the QML GUI like this:
QQuickView viewer;
viewer.setSource(QUrl("./qml/main.qml"));
viewer.show();
then I added myClass and got me an object to do the connections:
MyClass myClass;
QQuickItem* item = viewer.rootObject();
QObject::connect(item, SIGNAL(buttonClicked()), &myClass, SLOT(mySlot()));
QObject::connect(&myClass, SIGNAL(mySignal(QVariant)), item, SLOT(updateGUI(QVariant)));
When implementing the slots and signals in the C++ classes you must use QVariant objects to transfer the data. The QML file then implements SIGNALS e.g. for clicked buttons and SLOTS to receive data to display.
This is exactly what I was hoping for. The only change to my non GUI code was to do all the interactions via SIGNALS and SLOTS. Now I can even use both GUIs (QML / Widgets) for my application.
Just write your core logic in C++, interface it with signals and slots, and you can use the same component with widgets and also with QML.
It is not rocket science, C++ logic allows usage with C++ and QML, JS logic - only QML. C++ and the Qt API is the more sound solution, because from JS you don't really have access to that much functionality of the Qt APIs, only a few methods are "ported" into the QML world. But all the high performance data containers and the execution performance itself is in C++.
If you only need to display results and console is not good enough, I'd rather keep to QtWidgets, because adding the declarative module slows compilation down significantly. The widget module is standalone now, so you are adding "extra" module even with QtWidgets (in Qt4 it was part of QtGui) but it is lighter. After you use widgets for prototyping your core logic, you can then implement a QML interface and just hook that up to the existing signals/slots/properties and bindings using them.
And no, you don't embed QML in C++ classes, it is the other way around, C++ is the more low-level layer, which is used to create QML components. As for the actual instantiation, you can go both ways - if you register a QObject based class to the QML engine, you can instantiate it in QML. Or you could instantiate the class in C++ and only make it available in the QML context - it doesn't really matter. If you need a single object, you better instantiate it in C++ in the main() function and make it available in the QML context, if it is components you intend to instantiate a lot - then create a QML component.
You could prototype the core logic with JS in QML and later port it to C++ if you want too. It looks like twice the effort, but if you make your bed right it is actually a productivity increase, because prototyping is that much faster in QML, catching errors is much safer and informative, and if you make your API well, porting the JS code to C++ is usually a minor nuisance - replace some vars with concrete types, replace some . with -> and stuff like that.
Any "elaborate calculation" you really WANT to ultimately do in C++. Every time the calculation is completed, you can simply emit it as a signal, and automatically display the result to whatever slot the signal is connected, be that in a widget or in QML, or even both at the same time.
This is very opinion based. No 'true' answer possible. For me it is 'easier' to write in QML and 'extend' qml with Qt plugins. That's because I did a big project this way. Others might have other experiences and might because of that like a different approach. None of our 'life stories' could help you much.
I'm fairly new to Qt, and am trying to wrap my head around signals and slots. Though I've figured out how to create custom slots, I've yet to figure out how do update the GUI from my C++ code. I realized that the entire UI, which I created in the designer, is only written in what appears to be XML based UI code. Do I have to handwrite my own Qt C++ UI in order to update the interface, or can I somehow use C++ to update the XML based UI? I'm just looking to add a widget to the main form on a button click. Any help is appreciated. Thanks!
To add a widget to a form you can simply do
ui->layout()->addWidget(new Widget);
XML is used by QtDesigner as a mean to create, update, and persist your GUI, enabling a visual approach to development, but in the end you can build your application entirely without it.
you dont havfe to update the xml of UI . you can inherit the ui into your own class using setupUi
http://crpppc19.epfl.ch/doc/qt4-doc-html/html/qwidget.html#setupUi
now in your C++ class you can update the widgets like changing label text, lineEdit text, setting up spinbox value using Signals & slot.
That xml is used by Qt designer and outside of designer it's only used by uic as a source to generate C++ code, so everything that you do in the designer end-up as C++ code, so it can be updated (or done completely) in C++ code (you can look into the code and see that you most likely have a member called ui that is most likely a pointer, but it can also be an instance of a C++ class that is generated for you by uic, and trough that ui member you can access the widgets and layouts that you created in the designer).
A generic resource that i recommend you to read can be found here and then (if you still can't figure it out) ask a specific question about what exactly are you trying to achieve.
LE: that link contains 3 methods to use the generated code into C++ code, don't try all of them into your working project, you may choose one method or use the default one (ui member pointer)
Is there a way to find a GTKWidget by a control name / or id, from within the current window scope from a c/c++?
In Winforms, you had something like this:
public class Form1 : Form
{
public void Test()
{
this.Controls.Find("ControlName");
}
}
You can set names on widgets, using gtk_widget_set_name(), but I don't think there are built-in functions to find widgets in hierarchies based on the name.
That wouldn't be too hard to write if you had a need, though.
As Micah pointed out, it's not how GTK+ applications are generally structured, it's way more common to keep pointers to needed widgets from the time they were created, for manually built UI:s.
In GTK+ we store references to any widget we may need to access in later code using a variable (or struct/class/etc.) that is passed around as user data in the relevant callback functions. If you are using a UI builder (such as glade) then yes, there would be a way to reference the widget by the name you gave it in the UI builder. Otherwise, the answer is that there is not a way to "find" the widgets quite like that.
If you could provide a more specific example I could elaborate.