This release contains a big update to how NodeGui manages the memory and lifecycle for QObject
instances and their subclasses.
Note: These changes are NOT 100% backwards compatible with previous versions of NodeGui.
Highlights
- JS side object hierarchy is now much closer to the Qt C++ API.
Node*
in between classes are gone. EveryQObject
is a subclass ofQObject
on the JS side just like in Qt C++. - Destruction of
QObject
instances is tracked and propagated to the JS wrappers resulting in fewer complete crashes / segfaults and replacing them with more useful null object exceptions on the JS side. - Added
QObject
methods related to object trees.QObject.parent()
andQObject.children()
return wrappers of the correct subclasses. - Wrappers in JS and on the C++ side are cached and only one is made for each backing C++ object. This results in less memory use, a speed increase, and now wrapper object identity tests are correct. i.e.
myWidget.parent() === myWidget.parent()
. - Eliminated most stashing of object references in the JS wrappers. i.e. fewer memory leaks.
- Added tools for debugging memory problems.
Detailed API Changes
On the JavaScript / TypeScript side were these changes:
- Added
QObject.children()
- Added
QObject.parent()
- Added
QObject.delete()
- Added
QObject.deleteLater()
- Removed
NodeObject
, useQObject
instead. - Removed
NodeWidget
, useQWidget
instead. - Removed
NodeFrame
, useQFrame
instead. - Removed
NodeLayout
, useQLayout
instead. - Removed
NodeDateTimeEdit
, useQDateTimeEdit
instead. - Removed
NodeDialog
, useQDialog
instead. - Removed
NodeTextEdit
, useQTextEdit
instead. - Removed
NodeListView
, useQListView
instead. - Removed
NodeTableView
, useQTableView
instead. - Removed
NodeHeaderView
, useQHeaderView
instead. QWidget.layout
is no longer a property, it is a method like in C++ Qt, i.e.QWidget.layout()
. Changing it is done withQWidget.setLayout()
.- The flexbox support in
QScrollArea
caused some weird bugs but they have been fixed. If you need a flexbox layout inside aQScrollArea
then add a single content widget use flexbox on its children.
Upgrade Notes for Application Developers
The biggest change for applications is the removal of Node*
classes. Replace mentions of these classes with their normal Qt counterparts. See "Detailed API Changes" above.
Upgrade Notes for Plugin developers
This version is mostly likely not backwards compatible on a binary level. You should update your plugin to require this version of NodeGui and then fix any errors.
There are some changes needed to update wrappers for QObject
subclasses.
Registering wrappers
C++ wrapper classes should use the QOBJECT_REGISTER_WRAPPER
macro in their init()
method to register the mapping from a QObject
subclass to a C++ wrapper.
For example, in qdial_wrap.cpp
we have:
QOBJECT_REGISTER_WRAPPER(QDial, QDialWrap);
This says that instances of QDial
can be wrapped with QDialWrap
. This mapping is used by methods such as QObject.parent()
and QObject.children()
which need to take opaque C++ objects and wrap them before returning them.
The same needs to happen on the JS side too. In the matching wrapper JS class, the JS wrapper needs to be registered with wrapperCache
, mapping it to the name of its C++ wrapper counterpart. For QDial
this looks like:
const { wrapperCache } = require("@nodegui/nodegui");
// ...
wrapperCache.registerWrapper('QDialWrap', QDial);
Using the C++ Wrapper Cache
Finally, if you have a wrapper which needs to return another QObject
instance, you can use the wrapper cache directly and let it choose the correct wrapper or a cached one. The implementation of QObject.parent()
demonstrates this:
Napi::Value parent(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
QObject* parent = this->instance->parent();
if (parent) {
return WrapperCache::instance.getWrapper(env, parent);
} else {
return env.Null();
}
}