Home » Archived » EGL Development Tools » How can I manage widget instances?
How can I manage widget instances? [message #878754] |
Tue, 29 May 2012 21:34  |
Eclipse User |
|
|
|
I've been working on a small application written using EDT 0.8M1 and noticed some unexpected behaviour.
I often use the following method to create new child widgets:
ui.children = [ new Box{ height=100, width=100, backgroundColor="Red" } ];
If I repeat this statement a number of times I've found that the previous instances of the Box widget (in this example) continue to exist. I noticed this because of some InfoBus broadcasts I was using to communicate between widgets.
I can see the dilemma ... when should that box widget be destroyed. But in my example I believe that as soon as I execute the same statement, replacing the children in the ui widget, I have no way of referencing the first Box widget instance.
Is this behaviour expected?
Is there a way of managing widget instances?
Richard
|
|
| |
Re: How can I manage widget instances? [message #881302 is a reply to message #878754] |
Mon, 04 June 2012 10:03   |
Eclipse User |
|
|
|
Hi Sorry for the late response.
I investigate the Destory widget process in Gridlayout.
If you always use
ui.children = {new Box{..}} without located in any cell of GridLayout?
In initTable() method, children of table will be destoryed, I write a sample, not sure if what you required.
1. 'Button' & 'Box' are the children of ui.
2. When click 'Button', then the children of gridLayout will be 'change' widget only.
**************************************************
package client;
// RUI Handler
import org.eclipse.edt.rui.widgets.Box;
import org.eclipse.edt.rui.widgets.GridLayout;
import org.eclipse.edt.rui.widgets.GridLayoutData;
import org.eclipse.edt.rui.widgets.Button;
import dojo.widgets.DojoButton;
//
//
handler bb type RUIhandler{initialUI =[ui
], onConstructionFunction = start, cssFile = "css/v.css", title = ""}
ui GridLayout{columns = 3, rows = 4, cellPadding = 4, children = [ Button, Box ]};
Box Box{ layoutData = new GridLayoutData{ row = 3, column = 2 }, padding=8 };
change Button{ layoutData = new GridLayoutData{ row = 4, column = 2 }, text="Normal Button, Children of GridLayout" };
Button DojoButton{ layoutData = new GridLayoutData{ row = 4, column = 2 }, text = "Change Children", onClick ::= Button_onClick };
function start()
end
function Button_onClick(event Event in)
ui.children = [change];
end
end
******************************************************
If this is what you required, pls provide me some of your sample usage. Thanks.
|
|
|
Re: How can I manage widget instances? [message #881348 is a reply to message #881302] |
Mon, 04 June 2012 11:37   |
Eclipse User |
|
|
|
Hi,
I didn't fully understand what you were saying but below I've included a sample that illustrates my point/question.
The first source is for a main rui handler. This displays two buttons; one to add a new box child to my main handler, replacing the previous children and the second will publish an infobus request to the widget children asking them to say hello.
The second source is for my widget that will be added as a child of the main handler when the 'add box' button is pressed.
If you try this and then press the 'add box' n times and then press the 'say hello' button you will get a response from all of the added widgets, so they still exist.
My question revolves around the use of the following code, to add a child. By using this code it appears that I then unable to destroy that child widget.
container.children = [ new TestWidget{ height=100, width=100, backgroundColor=boxColour, children=[ new HTML{ text = "I am box number " :: boxNumber } ], boxNumber=boxNumber } ];
Is there a way I can destroy that child widget?
Is this behaviour expected?
Is there some method I should be using to manage new widget instances?
I hope that makes my question(s) clearer.
Richard
****************************************************
package client;
import org.eclipse.edt.rui.infobus.InfoBus;
import org.eclipse.edt.rui.widgets.Button;
import org.eclipse.edt.rui.widgets.Div;
import org.eclipse.edt.rui.widgets.HTML;
handler TestParent type RUIhandler{initialUI =[ui], onConstructionFunction = start, cssFile = "css/stocks.css", title = "TestParent"}
ui Div{children =[addboxButton, sayhiButton, container]};
container Div{ children=[] };
addboxButton Button{ text="Add Box",onClick::=addBox };
sayhiButton Button{ text="Say Hello",onClick::=sayHi };
boxNumber int = 0;
function start()
end
function addBox(e event in)
boxNumber += 1;
boxColour string;
case(boxNumber%3)
when(1)
boxColour = "Red";
when(2)
boxColour = "Blue";
otherwise
boxColour = "yellow";
end
container.removeChildren();
container.children = [
new TestWidget{ height=100, width=100, backgroundColor=boxColour,
children=[ new HTML{ text = "I am box number " :: boxNumber } ],
boxNumber=boxNumber } ];
end
function sayHi(e event in)
InfoBus.publish("SayHello", "Hello from box number ");
end
end
****************************************************
package client;
import org.eclipse.edt.rui.infobus.InfoBus;
import org.eclipse.edt.rui.widgets.Div;
handler TestWidget type RUIWidget{targetWidget = ui, onConstructionFunction = start, cssFile = "css/stocks.css", @VEWidget{category = "Custom"}}
ui Div{ children = [container] };
container Div{ children = [] };
boxNumber int;
function start()
InfoBus.subscribe("SayHello", SayHello_callback);
end
function setChildren(widgets widget[] in)
container.children = widgets;
end
function SayHello_callback(eventName string in, data any in)
sysLib.writeStdout(data as string :: boxNumber);
end
end
****************************************************
|
|
|
Re: How can I manage widget instances? [message #882097 is a reply to message #881348] |
Tue, 05 June 2012 21:01   |
Eclipse User |
|
|
|
Richard,
In your example, both the TestParent handler and the InfoBus Library are holding a pointer to your TestWidget handler, with TestParent holding a direct pointer to the TestWidget, and InfoBus holding an 'indirect' pointer via the callback function 'SayHello_callback'. When you reset the children of the container div in TestParent.addBox, you are breaking the link from TestParent to TestWidget, but the InfoBus is still holding this link as you have discovered.
In this situation, I believe you will either need to let the TestParent manage the subscribing and unsubscribing of the TestWidget with the InfoBus, or you will need to add a function to TestWidget that you can invoke from TestParent to 'cleanup' the TestWidget when it is no longer needed. Once an object is no longer being referenced by any other objects, the JavaScript garbage collector will automatically reclaim the memory associated with the object.
It is also worth mentioning that in addition to managing the InfoBus subscription, you will also need to tell the Rich UI runtime framework that a widget is no longer needed, so that the DOM elements associated with the widget can be discarded. To do this in your example, I believe you will need to do something like the following:
theChildren Widget[] = container.children; // hold onto the children
container.removeChildren(); // remove them from the container
for(i int from 1 to theChildren.getSize())
UtilLib.destroyWidget(theChildren[i]); // destroy the children
end
Invoking destroyWidget is necessary because some older browsers are unable to reclaim the memory of JavaScript objects that are holding references to the DOM tree, which can cause a memory leak if the browser window is refreshed since all of the widget objects cannot be reclaimed. To work around this issue, the Rich UI Runtime keeps track of all widgets that are created and automatically destroys them when the application is terminated. During the destroy process, all of the DOM elements associated with the widget, and its children, are separated from their corresponding JavaScript objects so that the memory can be reclaimed.
If an application creates and discards widgets as part of its normal processing, these discarded widgets will appear as memory leaks in the runtime until the application is terminated. An alternative to invoking destroy in this situation is to re-use as many widget instances as possible, instead of creating new widgets, but in some cases it may be necessary for a widget to be destroyed using the UtilLib functions.
-Brian
|
|
|
Re: How can I manage widget instances? [message #882434 is a reply to message #882097] |
Wed, 06 June 2012 13:06   |
Eclipse User |
|
|
|
Brian,
Many thanks for the info. I'll write some code within my widgets to issue an infobus.unsubscribe when I want to destroy the widget.
Is there someplace that I can see the widgets that have been created within my application? You mention that the rui runtime keeps track of the widgets as they are created. I've had a quick look at the dom using FireBug but I couldn't obviously find my widgets.
Richard
|
|
| |
Re: How can I manage widget instances? [message #882578 is a reply to message #882465] |
Wed, 06 June 2012 19:13   |
Eclipse User |
|
|
|
Brian,
In addition to egl.elements I also found OpenAjax.hub._subscriptions and when I unsubscribe I can see the subscriptions disappear from this section but the widgets still remain within the egl.elements section.
Does that mean that there is still some link that is stopping these objects from being destroyed?
How can I tell whether there is a link to these objects that is stopping them from being destroyed?
I haven't tried the destroyWidget function yet as I've tested this on the latest versions of both Firefox and Chrome.
Richard
|
|
|
Re: How can I manage widget instances? [message #883056 is a reply to message #882578] |
Thu, 07 June 2012 18:53   |
Eclipse User |
|
|
|
Richard,
OpenAjax.hub._subscriptions maintains the subscriptions that you are manually defining in your application when using InfoBus.subscribe(), and it is important that you unsubscribe any widgets that you are no longer using so that they can be garbage collected.
Any elements that you create are also automatically added to the egl.elements array by the Rich UI runtime when they are created, and are only removed from this array when the application is terminated or when UtilLib.destroyWidget() is invoked.
In general, a widget can only be garbage collected by the browser when it is no longer being referenced by the application. All widgets that are no longer being used should be destroyed using UtilLib.destoryWidget(), but before destoryWidget is invoked, "manual" references to these widgets should also be removed from the application, which could include InfoBus subscriptions, storage in an array of another widget or handler, etc.
In the future, it would be best if the Rich UI Runtime can be updated to automatically invoke destroyWidget on elements of the array that are no longer being referenced by an application, but for now this has to be invoked manually.
-Brian
|
|
|
Re: How can I manage widget instances? [message #883394 is a reply to message #883056] |
Fri, 08 June 2012 12:43   |
Eclipse User |
|
|
|
Brian,
Thanks for your help and the information you've provided.
I'll have a go at implementing the destroyWidget function within my widgets and execute this when I know I've finished with the widget, possibly building a destroyChildren function that performs similar steps to those you outlined.
However, would the following code also destroy the children of theChildren? I'll test this.
for(i int from 1 to theChildren.getSize())
UtilLib.destroyWidget(theChildren[i]); // destroy the children
end
Many Thanks
Richard
|
|
| |
Goto Forum:
Current Time: Wed Feb 12 07:34:35 GMT 2025
Powered by FUDForum. Page generated in 0.04027 seconds
|