Is it possible move JavaFX nodes between Parents in newer versions of JavaFX? - javafx

JavaFX 19,
Apparently we used to be able to move a javafx node to a new parent using parent.getChildren().add(node). However, getChildren is now protected making it inaccessible. I also tried changing its accessibility using trySetAccessible(), but this returns false indicating the method is not capable of being set to accessible. What I'm wondering is how am I supposed to move nodes from one parent to another now that getChildren is no longer available?
For example, if I have a Kotlin method:
fun moveNode( parent: Parent, child: Node) {
//First remove child from current parent
child.parent.getChildren().remove(child)
//Then add child to new parent
parent.getChildren().add(child)
This seems like such a useful action for turning traditional applications into dynamic programs, I'm also curious why JavaFX no longer allows it. Thanks for all the help!

You must have messed up something there. I can't see anything that has been changed here since JavaFX 8. Parent has a protectrd children property and a protected getChildren() method which you cannot directly access from some other class and Pane has a public getChildren() method which can be accessed directly from anywhere.

I think I found an answer, but please somebody fact check me on this. Pane objects (which inherit from Parent and Node) replace the getChildren method with a public version. As far as I can tell, only Pane's have accessible children, and are intended to be used this way. So all I have to do is make sure I am ALWAYS moving nodes to a Pane, instead of Parent like in the example above.
Also looks like getChildren() was replaced with children property.
fun moveNode( parent: Pane, child: Node) {
//First remove child from current parent
child.parent.children.remove(child)
//Then add child to new parent
parent.children.add(child)
Update: According to AI, all these Parent objects have accessible getChildren methods...
Pane (and its subclasses: FlowPane, GridPane, HBox, StackPane, TilePane, VBox)
Group
CustomNode (and its subclasses)

Related

Issue regarding setting parent of widget in Qt

From this post here, in general:
All QObjects will delete their own child objects automatically. (See
docs here.) QWidgets are QObjects. So as long as you establish a
parent/child relationship, you do not need to manually delete your
objects. To do that, simply pass a pointer to the parent object to the
constructor:
QLabel *label1 = new QLabel; // <<- NEED TO DELETE
QLabel *label2 = new QLabel(some_parent_obj); // Will be deleted when some_parent_obj is deleted
So some questions arises:
Does every widget necessary needed/required a parent? If no, what are the exceptions? If yes, what happens to widgets without parent?
I asked this because from examples in Qt Docs, some example widgets have parents (QLabel example) but some doesn't (QBarChart example, and also QFont, QColor, etc...).
So I'm wondering if there's an exception, or those widgets just don't need any parents, or if I declare them with new for some reason, I have to delete afterward.
And vice versa...
Does a widget without parent guarantee to cause a memory leak (or something similar) when the widget which it stays in (not necessary its parent) is deleted? Or if it's removed from a layout without any deletion happening?
Because from my experience with my code, I've created probably quite a lot (~100) of widgets and other stuffs without neither setting any parent (nor using delete afterward), and the project appears to run fine without any stalls even after a while (the effect might be underlying though, as I haven't run Memcheck), hence this question is here.
Does every widget necessary needed/required a parent?
If you want them to be deleted automatically - yes. But...
If no, what are the exceptions? If yes, what happens to widgets without parent?
You do not need to provide a parent to widget if you attach it to layout using QLayout::addWidget. If you look into source code, you'll see that when you do so, it automatically attaches layout's parent as widget's parent(unless you didn't attach layout to any widget).
But if you leave the widget created with new without parent and do not attach to anything - it is leaking memory. You must delete it either using delete or QObject::deleteLater. The last option is recommended when object has any connections.
Does a widget without parent guarantee to cause a memory leak (or something similar) when the widget which it stays in (not necessary its parent) is deleted? Or if it's removed from a layout without any deletion happening?
As I already mention QLayout::addWidget sets parent for added widget, so the answer is no. Also note, that when you call QLayout::removeWidget, it removes only QLayoutItem from layout, but widget's parent stays the same as it was after calling QLayout::addWidget.

JavaFX children vs items

Why in JavaFX some controls and layout has "children" property, when other has "items" property for essentailly same purpose? Is there any philosophy behind or may be some technical difference?
The getChildren() method is defined in Parent, and consequently inherited by all subclasses of Parent, including Pane, and Control. The implementation of this method in Parent returns an unmodifiable list of child nodes (so it can be used for navigation through the scene graph, but cannot be used to manipulate what is contained in the parent).
The Pane class, and its subclasses, are designed to allow you to lay out other nodes in the scene graph. So Pane overrides getChildren() to return a modifiable list of these nodes: essentially the functionality of a Pane is to allow you to add nodes to it and remove them later if you need. The Pane subclasses position these nodes in various ways.
The Control class is a subclass of Parent, as controls contain other nodes. (E.g. a ComboBox contains a label or text field (if it's editable), and a button for displaying the drop down list.) Control inherits its getChildren() method from Parent, so it returns an unmodifiable list of the child nodes, but doesn't allow you to change that list (because if you removed nodes from a control, it would no longer behave in the way that control was designed to behave).
Some controls are designed to display other content. Trivially, a Label or Button can have a graphic, which is any node. The API for these classes allows you to change that node (via setGraphic()).
More complex controls allow you to add and remove a collection of nodes, as part of their intended functionality. So for example a SplitPane allows you to add as many nodes as you like, and remove them if you need. However, these are not the only nodes contained in the SplitPane. So the getChildren() method still has its implementation from the superclass: it returns an unmodifiable list of all the child nodes of the split pane: that includes the items you add, and the dividers (and potentially other things too). On the other hand, the getItems() method returns the list of nodes that you are allowed to change: so you can remove an item by calling splitPane.getItems().remove(...) (and the split pane will remove the corresponding divider from its child list as well).
Other complex controls have getItems() methods that might return specific types: e.g. Menu.getItems() returns an ObservableList<MenuItem> (so you can't put a TableView in a menu, you can only put menu items in there). Similarly TabPane.getItems() returns an ObservableList<Tab>.
So in short, the two things have completely different functionality. getChildren() returns the list of child nodes for the parent: it allows you to inspect and navigate the scene graph. Parent subclasses that specifically choose to do so may return a modifiable list, allowing you to use them as general containers.
The getItems() methods that some Control classes define are there to define specific functionality of that particular control. They still have getChildren() methods, which will return a different list.

JavaFX nodes - How to make them resizable by the end user?

I am developing a JavaFX application where a class I have developed (extended from javafx.scene.Parent) is created on-the-fly based on what entry the user has clicked in a ListView control.
Just to be clear about this node, it is not created using a layout tool like SceneBuilder, it is created at runtime based on the user's actions.
The constructor for my custom node class creates a VBox and a Label and uses passed coordinates (X,Y) in the constructor method to set its own Layout coords. I then use a custom utility class to make the node draggable. This new node is then added to the main application Pane.
However, I have failed to find out how I can make these nodes resizable by the user. That is, allow the user to mouse over the corner of the node, hold and drag to resize. An operation that all users are used to, no matter what the OS.
Has anyone done anything like this in JavaFX? (My searches on the subject only seem to pull up subjects on the automatic resizing that a parent node does with its child nodes.)
Many thanks,
Ian.
As you can see on the documentation of VBox you can only define minimum, prefered and maximum range, there's not really a way to make it manually resizable.
The only proper solution to solve your problem is to develop your own class to do it, because what you want seems very specific, with your problem description, I don't think use some layouts or panels will do what you exactly want.
I found something that you can use : Dragging to resize a JavaFX Region
This allows you to resize a region, all you have to do after is to put you VBox in this region, but notice in this article that :
Only height resizing is currently implemented.
This code won't work in JavaFX8, you'll have to check the comment to see how it worls in JavaFX8
Hope this helps.

About deleting, removing widgets and layouts in Qt 4

(I use Qt 4.7, Windows 7, 64bit).
I created a custom table. Each row is a horizontal layout with widgets.
The rows are kept in a QList for easy access, and the children too. The rows are also added inside the parent widget.
If I resize the parent widget, I calculate the new sizes, delete everything, and recreate it again.
My problem is that I don't want to delete any widget. Only when I clear the table, I do it.
Since I have the widgets inside a QList and inside the parent layouts, How can I remove all widgets in each row, delete all layouts, and then add those to new layouts?
If I do: takeAt(0) for every element inside each layout I have a QLayoutItem with a widget inside... How can I delete the layoutItem without deleting the widget?.... How do I remove the widget without killing it, no matter if it's in the parent or the child? Because there are many methods for deleting: removeItem, removeWidget... in a layout, but not takeWidget... just takeAt() and it gives a Qlayoutitem.
I tried several ways, but I still see the widgets no matter what happened to them.
Questions about this:
When does a widget get deleted? If I takeWidget(index) from a layout, is it deleted some time by itself? does it happen if I have a pointer to it in another list?
removeAt(index) does execute the delete method of a widget?
Ok. I got it working.
Let me explain how this Removing, keeping widgets works.
A widget is known by its parent layout. And you remove it through the layout. By doing:
layout()->removeAt(widget);
delete widget;
If you use takeAt(index) in a QLayout (or its children), it gives you a QLayoutItem. To access the widget inside, just use widget(). But there's no way to remove the widget without deleting it. So this approach is non valid.
In the Docs it tells a way to delete the elements:
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
...
delete child;
}
A special thing to note in Qt is the following:
If you have a hierarchy tree of layouts, added with addLayout() inside layouts, no matter how deep your widget is inserted, you can remove it from the child layouts or any of the parent layouts, if the tree path from the layout and this item is built from child layouts.
The easiest thing is to keep a list of pointers to all the items, in a custom table. When clearing the table to reconstruct it, just do this inside your widget:
CustomTableItem* item;
while ( !items_.isEmpty() && ( (item = items_.takeFirst()) != 0 ) ){
layout()->removeWidget(item);
delete item; // It works no matter where the item is
}
items_.clear(); // clear the list afterwards.
And it works perfectly, updates the layout too by itself.
If you want to keep the elements, just skip the "delete item;" and use them afterwards.
An important thing to note is that different "remove" functions work differently (as i understand on Qt Docs) in QList or similar widgets, and in a QLayout.
In the QList, removeAt actually removes the object.
(Qt 4.7 QList Docs)"Removes the item at index position i. i must be a valid index position in the list (i.e., 0 <= i < size())."
In a QLayout, removeWidget or removeItem don't remove the item/widget, you have the responsability to delete it, as I did before.
(Qt 4.7 QLayout Docs) "Removes the widget widget from the layout. After this call, it is the
caller's responsibility to give the widget a reasonable geometry or to
put the widget back into a layout."
Hope it helps. If you see any error, you could tell me and I will edit the answer!
More on deleting here:
Other stackoverflow post
A widget in Qt is a regular C++ object and can be deleted with the C++ delete operator as any other object:
delete myWidget;
In Qt there is always a parent-child relation between widgets. When the parent widget is destroyed, it will delete all its children. Usually, you do not need to think about explicitly deleting any widgets but the top level widgets, i.e., windows and dialogs. Qt will take care of deleting any child widgets.
QList::removeAt(int) does not delete the object that is removed, it only removes the object from the list. If you also want to delete the object you would have to do something like:
delete myList.takeAt(0);
This applies to all functions such as removeAt(int), takeAt(int), takeFirst(), etc. They never delete objects, they only remove them from the container (list, layout, scrollarea, etc). In most cases the ownership of the widget is then transferred to the caller, (the caller becomes responsible for deleting the widget as the parent-child relation breaks), but do not assume this is always the case, always read the documentation of the function.

How to remove widget from another Qwidget?

i created one QWidget(Parent). in the inside of the parent widget i created another one QWidget(Child). In the run time i need to remove the child widget. how to do that?
i am not using any layout. i am directly putting in the Parent Widget.
Please Help me to fix this.
If you add the widget with e.g.:
QWidget *w = new QWidget(parent);
...then you can remove it with:
delete w;
Another approach would be to just hide it:
w->hide();
This answer is for those arriving from search engines and want an answer to the question as stated in the title.
If you want to remove a child from a parent without deleting it or hiding it (which does NOT remove it from its parent), set the child's parent to NULL.
QWidget::setParent(NULL)
Note that explicitly reparenting a widget like this carries several implications (e.g visibility automatically set to hidden). See QWidgets documentation for more information.

Resources