Skip to main content



      Home
Home » Eclipse Projects » Standard Widget Toolkit (SWT) » Disposing of parent when last child is gone
Disposing of parent when last child is gone [message #370465] Fri, 30 May 2003 19:39 Go to next message
Eclipse UserFriend
I have a Composite that I want to dispose of when it's last child is
gone. Here is the problem:

Widget get's it's dispose() called, tells it's DisposeListeners.
Parent tries to do dispose() self, must dispose children first.
Widget get's it's dispose() called, tells it's DisposeListeners.
Parent tries to do dispose() self, must dispose children first.
Widget get's it's dispose() called, tells it's DisposeListeners.
Parent tries to do dispose() self, must dispose children first.
...

This makes sense, otherwise you could never call getParent() in
DisposeListener.widgetDisposed(). A DisposeEvent also cannot be
canceled, since it doesn't have a "doit" instance variable. For such a
low-level event that also makes sense. I wouldn't really ever expect a
dispose() to fail unless there was some major problem.

I tried removing the DisposeListener at the start of widgetDisposed(),
but then I get another problem. Disposing of the parent disposes the
child first, then the parent, and then control goes back to the child
after it called it's DisposeListeners. It then tries to dispose()
itself, which throws an exception, since it's parent already disposed it.

So, the question is how to get around this? How can I get the
DisposeEvent AFTER it has completed? Do I have to start a new thread,
watch my container until it has 0 children, then re-join the UI thread
and dispose of it? Ouch!

Here's a snippet:

/* Main.java */
package com.cormier.tools.swt;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Main {
final static boolean expand= false;
public static void main(String[] args) {
Display display= new Display();
Shell shell= new Shell(display);
shell.setLayout(new FillLayout());

SashForm form= new SashForm(shell, SWT.HORIZONTAL);
new Button(form, SWT.NONE).setText("Button 1");

Composite comp= new Composite(form, SWT.NONE);
comp.setLayout(new FillLayout());
Button button= new Button(comp, SWT.PUSH);
button.setText("Button 2");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent se) {
Button source= (Button)se.getSource();
Composite parent= source.getParent();
source.setVisible(false);
source.dispose();
parent.layout(true);
se.detail= SWT.ABORT;
}
});
button.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent de) {
((Button)de.getSource()).removeDisposeListener(this);
Composite target=
(Composite) ((Button)de.getSource()).getParent();
Composite parent= target.getParent();
target.setVisible(false);
System.out.println("disposing parent");
target.dispose();
System.out.println("parent disposed");
parent.layout(true);
}
});

shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Re: Disposing of parent when last child is gone [message #370466 is a reply to message #370465] Fri, 30 May 2003 20:17 Go to previous messageGo to next message
Eclipse UserFriend
Here is what I came up with:

public class DelayedDisposeListener extends Thread implements
DisposeListener {
Composite comp;
public DelayedDisposeListener() {
}
public void widgetDisposed(DisposeEvent event) {
if(event.widget instanceof Control) {
comp = ((Control) event.widget).getParent();
comp.getDisplay().asyncExec(this);
}
}
public void run() {
if(comp == null)
return;
while(comp.getChildren().length > 0);
if(comp.isDisposed())
return;
Composite parent = comp.getParent();
comp.setVisible(false);
comp.dispose();
parent.layout(true);
}
}

However, this would have been much easier with something like
java.awt.event.ContainerAdapter.

Composite.addCompositeListener(new CompositeListener() {
public void childAdded(CompositeEvent event){}
public void childRemoved(CompositeEvent event){}
});

Buddha wrote:
> I have a Composite that I want to dispose of when it's last child is
> gone. Here is the problem:
>
> Widget get's it's dispose() called, tells it's DisposeListeners.
> Parent tries to do dispose() self, must dispose children first.
> Widget get's it's dispose() called, tells it's DisposeListeners.
> Parent tries to do dispose() self, must dispose children first.
> Widget get's it's dispose() called, tells it's DisposeListeners.
> Parent tries to do dispose() self, must dispose children first.
> ...
>
> This makes sense, otherwise you could never call getParent() in
> DisposeListener.widgetDisposed(). A DisposeEvent also cannot be
> canceled, since it doesn't have a "doit" instance variable. For such a
> low-level event that also makes sense. I wouldn't really ever expect a
> dispose() to fail unless there was some major problem.
>
> I tried removing the DisposeListener at the start of widgetDisposed(),
> but then I get another problem. Disposing of the parent disposes the
> child first, then the parent, and then control goes back to the child
> after it called it's DisposeListeners. It then tries to dispose()
> itself, which throws an exception, since it's parent already disposed it.
>
> So, the question is how to get around this? How can I get the
> DisposeEvent AFTER it has completed? Do I have to start a new thread,
> watch my container until it has 0 children, then re-join the UI thread
> and dispose of it? Ouch!
>
> Here's a snippet:
>
> /* Main.java */
> package com.cormier.tools.swt;
>
> import org.eclipse.swt.SWT;
> import org.eclipse.swt.custom.SashForm;
> import org.eclipse.swt.events.DisposeEvent;
> import org.eclipse.swt.events.DisposeListener;
> import org.eclipse.swt.events.SelectionAdapter;
> import org.eclipse.swt.events.SelectionEvent;
> import org.eclipse.swt.layout.FillLayout;
> import org.eclipse.swt.widgets.Button;
> import org.eclipse.swt.widgets.Composite;
> import org.eclipse.swt.widgets.Display;
> import org.eclipse.swt.widgets.Shell;
>
> public class Main {
> final static boolean expand= false;
> public static void main(String[] args) {
> Display display= new Display();
> Shell shell= new Shell(display);
> shell.setLayout(new FillLayout());
>
> SashForm form= new SashForm(shell, SWT.HORIZONTAL);
> new Button(form, SWT.NONE).setText("Button 1");
>
> Composite comp= new Composite(form, SWT.NONE);
> comp.setLayout(new FillLayout());
> Button button= new Button(comp, SWT.PUSH);
> button.setText("Button 2");
> button.addSelectionListener(new SelectionAdapter() {
> public void widgetSelected(SelectionEvent se) {
> Button source= (Button)se.getSource();
> Composite parent= source.getParent();
> source.setVisible(false);
> source.dispose();
> parent.layout(true);
> se.detail= SWT.ABORT;
> }
> });
> button.addDisposeListener(new DisposeListener() {
> public void widgetDisposed(DisposeEvent de) {
> ((Button)de.getSource()).removeDisposeListener(this);
> Composite target=
> (Composite) ((Button)de.getSource()).getParent();
> Composite parent= target.getParent();
> target.setVisible(false);
> System.out.println("disposing parent");
> target.dispose();
> System.out.println("parent disposed");
> parent.layout(true);
> }
> });
>
> shell.open();
> while (!shell.isDisposed()) {
> if (!display.readAndDispatch())
> display.sleep();
> }
> display.dispose();
> }
> }
>
Re: Disposing of parent when last child is gone [message #370507 is a reply to message #370465] Mon, 02 June 2003 11:55 Go to previous message
Eclipse UserFriend
Originally posted by: steve_northover.ca.ibm.com

You could use Display.asyncExec() to queue a runnable for later.

"Buddha" <BuddhaBuddy@hotmail.com> wrote in message
news:3ED7EB9E.1040500@hotmail.com...
> I have a Composite that I want to dispose of when it's last child is
> gone. Here is the problem:
>
> Widget get's it's dispose() called, tells it's DisposeListeners.
> Parent tries to do dispose() self, must dispose children first.
> Widget get's it's dispose() called, tells it's DisposeListeners.
> Parent tries to do dispose() self, must dispose children first.
> Widget get's it's dispose() called, tells it's DisposeListeners.
> Parent tries to do dispose() self, must dispose children first.
> ...
>
> This makes sense, otherwise you could never call getParent() in
> DisposeListener.widgetDisposed(). A DisposeEvent also cannot be
> canceled, since it doesn't have a "doit" instance variable. For such a
> low-level event that also makes sense. I wouldn't really ever expect a
> dispose() to fail unless there was some major problem.
>
> I tried removing the DisposeListener at the start of widgetDisposed(),
> but then I get another problem. Disposing of the parent disposes the
> child first, then the parent, and then control goes back to the child
> after it called it's DisposeListeners. It then tries to dispose()
> itself, which throws an exception, since it's parent already disposed it.
>
> So, the question is how to get around this? How can I get the
> DisposeEvent AFTER it has completed? Do I have to start a new thread,
> watch my container until it has 0 children, then re-join the UI thread
> and dispose of it? Ouch!
>
> Here's a snippet:
>
> /* Main.java */
> package com.cormier.tools.swt;
>
> import org.eclipse.swt.SWT;
> import org.eclipse.swt.custom.SashForm;
> import org.eclipse.swt.events.DisposeEvent;
> import org.eclipse.swt.events.DisposeListener;
> import org.eclipse.swt.events.SelectionAdapter;
> import org.eclipse.swt.events.SelectionEvent;
> import org.eclipse.swt.layout.FillLayout;
> import org.eclipse.swt.widgets.Button;
> import org.eclipse.swt.widgets.Composite;
> import org.eclipse.swt.widgets.Display;
> import org.eclipse.swt.widgets.Shell;
>
> public class Main {
> final static boolean expand= false;
> public static void main(String[] args) {
> Display display= new Display();
> Shell shell= new Shell(display);
> shell.setLayout(new FillLayout());
>
> SashForm form= new SashForm(shell, SWT.HORIZONTAL);
> new Button(form, SWT.NONE).setText("Button 1");
>
> Composite comp= new Composite(form, SWT.NONE);
> comp.setLayout(new FillLayout());
> Button button= new Button(comp, SWT.PUSH);
> button.setText("Button 2");
> button.addSelectionListener(new SelectionAdapter() {
> public void widgetSelected(SelectionEvent se) {
> Button source= (Button)se.getSource();
> Composite parent= source.getParent();
> source.setVisible(false);
> source.dispose();
> parent.layout(true);
> se.detail= SWT.ABORT;
> }
> });
> button.addDisposeListener(new DisposeListener() {
> public void widgetDisposed(DisposeEvent de) {
> ((Button)de.getSource()).removeDisposeListener(this);
> Composite target=
> (Composite) ((Button)de.getSource()).getParent();
> Composite parent= target.getParent();
> target.setVisible(false);
> System.out.println("disposing parent");
> target.dispose();
> System.out.println("parent disposed");
> parent.layout(true);
> }
> });
>
> shell.open();
> while (!shell.isDisposed()) {
> if (!display.readAndDispatch())
> display.sleep();
> }
> display.dispose();
> }
> }
>
Previous Topic:dialog key listener
Next Topic:event from child to parent ?
Goto Forum:
  


Current Time: Sun Nov 09 18:36:15 EST 2025

Powered by FUDForum. Page generated in 0.03787 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top