www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.dwt - Events

reply Kyle Furlong <kylefurlong gmail.com> writes:
Currently, one has to write code like this:

private class MenuArgs
{
	Menu menu;
	Label label;
	this(Menu m, Label l)
	{
		menu = m;
		label = l;
	}
}

MenuArgs args = new MenuArgs(Menu, Label);
					 	
Label.handleMouseDown(args, delegate void(MouseEvent e)
{
	MenuArgs args = cast(MenuArgs)e.cData;
	// Do things with args.
});

But NOT like this:

Label.handleMouseDown(null, delegate void(MouseEvent e)
{
	// Do things with Label and Menu, and any other objects outside this scope.
});

Doing anything with objects outside of the scope of the delegate will cause
AccessViolations inside of the DWT eventable.d, 
unless they are passed as cData.

This seems to be an onerous restriction, and also counterintuitive. Also, all
the examples use objects outside the scope of the 
delegate as well, so that it would seem to be The Right Way, except that it
doesnt work.


Is this a bug? Or a feature?
Feb 07 2006
next sibling parent reply "Kris" <fu bar.com> writes:
"Kyle Furlong" <kylefurlong gmail.com> wrote ..
[snip]
 Is this a bug? Or a feature?

I suspect what's happening is that your out-of-scope MenuArgs are actually on the stack when you call handleMouseDown(), which is not the case when the delegate is invoked. Java handles such things by encapsulating the stack state, but D does not (for a variety of reasons). One way to resolve it is to change the approach such that MenuArgs becomes part of an enclosing class or struct around the handler, or otherwise becomes reachable from the handler (such as a static MenuArgs would be). Which examples are you referring to, Kyle? I ask because there's a couple of subtle concerns here.
Feb 07 2006
parent Kyle Furlong <kylefurlong gmail.com> writes:
Kris wrote:
 "Kyle Furlong" <kylefurlong gmail.com> wrote ..
 [snip]
 Is this a bug? Or a feature?

I suspect what's happening is that your out-of-scope MenuArgs are actually on the stack when you call handleMouseDown(), which is not the case when the delegate is invoked. Java handles such things by encapsulating the stack state, but D does not (for a variety of reasons). One way to resolve it is to change the approach such that MenuArgs becomes part of an enclosing class or struct around the handler, or otherwise becomes reachable from the handler (such as a static MenuArgs would be). Which examples are you referring to, Kyle? I ask because there's a couple of subtle concerns here.

I guess I am just searching for best practices. If someone can come up with The Right Way to handle events in DWT I would be happy. The examples I was referring to are the ones in the DWT distribution.
Feb 07 2006
prev sibling parent "Shawn Liu" <shawn666.liu gmail.com> writes:
It's not a bug. It is a tradeoff.

I spent some time to integrate D delegate to DWT. And eventually made it
possible to support both D Delegate and Java like Listener to handle an 
event;
Coexistence of delegate and listener can benefit port exists java project 
which
use listener. And new app can use either as suitable; The passed arguments
makes it possible to use anonymous delegate.

But anonymous delegate can not access stack object or event part of an
enclosing class/struct. This is because the install of delegate and invoke
the delegate occurs in different stack.

Anonymous listener can access variable of the enclosing class, but seems
can't access the enclosing class this pointer ( not sure )


assumed we have the class with Label and Menu variable
# class SomeClass {
# Label label;
# Menu menu;
# .....
# }


1) use delegate
  a) pass args as Kyle expressed, which is anonymous delegate
  b) use named delegate

# void foo(MouseEvent e) {
# // Do things with Label and Menu
# }
# label.handleMouseDown(null, &foo);


2) use listener

a) implement the listener interface by the class
# class SomeClass : SelectionListener {
# // implement the interface
# public void widgetSelected(SelectionEvent e){
# // Do things with Label and Menu
# }
# // install the listener
# label.addSelectionListener(this);
# }

b) create separated Listener class
Can be a separated class or inner class of the outer,
but still need pass the arguments in.
I am not sure whether inner class can access outer
class's member as Java does.

# class MyListener : SelectionListener {
# MenuArgs args;
# public this(MenuArgs args) { this.args = args; }
# public void widgetSelected(SelectionEvent e){
# // do things with args
# }

 c) anonymous listener
zwang gives an example in "sortindicator.d"
http://trac.dsource.org/projects/dwt/browser/trunk/current/win32/packages/dwt/examples/sortindicator/sortindicator.d?rev=96#L80



"Kyle Furlong" <kylefurlong gmail.com> 
says:dsb732$44v$1 digitaldaemon.com...
 Currently, one has to write code like this:

 private class MenuArgs
 {
 Menu menu;
 Label label;
 this(Menu m, Label l)
 {
 menu = m;
 label = l;
 }
 }

 MenuArgs args = new MenuArgs(Menu, Label);

 Label.handleMouseDown(args, delegate void(MouseEvent e)
 {
 MenuArgs args = cast(MenuArgs)e.cData;
 // Do things with args.
 });

 But NOT like this:

 Label.handleMouseDown(null, delegate void(MouseEvent e)
 {
 // Do things with Label and Menu, and any other objects outside this 
 scope.
 });

 Doing anything with objects outside of the scope of the delegate will 
 cause AccessViolations inside of the DWT eventable.d, unless they are 
 passed as cData.

 This seems to be an onerous restriction, and also counterintuitive. Also, 
 all the examples use objects outside the scope of the delegate as well, so 
 that it would seem to be The Right Way, except that it doesnt work.


 Is this a bug? Or a feature? 

Feb 08 2006