In several classes I have defined an “Open” event which I raise at the end of the constructor so that certain properties can be set or left as the default values from the constructor. However this event is never raised as expected so properties cannot be properly set. I got around this issue by adding a single action timer that calls the Open event almost immediately after the constructor, but this seems like an improper way to solve the issue. Is it possible to raise an event from the constructor of a class? Thanks.
Are you sure the code in your Constructor is running at all? Can you post its code?
Both the constructor and events are just methods at heart, so it certainly should work.
If you are calling the Open event from the Constructor you might either want to set your defaults in the Constructor method or just let the Open event happen normally…
Note that the event runs in a subclass or a window instance of your class, not in the class itself. I just tried raising an event in the constructor of a class and implementing the event in a subclass of that class, and it worked like it should.
The code from one of the class’s constructors:
mTimer = new Timer
mTimer.Period=1000/30
mTimer.Mode=Timer.ModeMultiple
mTimer.Reset
AddHandler mTimer.Action, AddressOf TimerAction
Patterns=new Dictionary
Gravity=new Vector2D
RaiseEvent Open
And the other class:
SetID(self)
Solid=msolid
Visible=mvisible
SetImage(pic)
ReferenceName=theName
Acceleration=new Vector2D
Velocity=new Vector2D
Position=new Vector2D
RaiseEvent Open
I put break points at the start of the constructor and stepped through it and the RaiseEvent was stepped over as expected but the break point I had placed in the Open event was never used. Although I could set the properties in the constructor I would prefer to let them be set in the Open event so that each instance can be unique. And the classes are added to window1 as window instances so that should not be the issue.
@Tim Hare: Did you try adding an instance of the class to a window and adding the Open event handler there or just in the subclass? I’m interested because a) thats what I’m trying to do and b) I’ve been having some weird errors occur recently (such as the app object becoming nil at runtime during debugging) and I’m wondering if I should try to reinstall Xojo. Thanks
No, I did not. I created a subclass. It appears that it does not work if you put it on the window and implement the event there. Seems to be a bug.
Well
lets see
You can’t add handler for events to instance unless they exist
But to make them exist you have to construct them
To create & populate a window with controls the code is like (it’s not this but this is close enough for illustration)
dim tmp as control = new control // this will call YOUR constructor for your new class
addControlToWindow tmp
addHandler tmp.event, method
and in this case the “method” being added is the OPEN event handler
Quite literally the OPEN event occurs BEFORE there’s a handler for it
RaiseEvent in the constructor happens before there a handler
Not sure there’s anything we could do about this
Ok thanks for the verification Tim and the explanation Norman. Would you be able to tell me how some of the controls (say the Canvas) allow the Open event to occur? I can get around the problem with a single action Timer, but there is probably a better way to go about doing this. Also can values be passed to the constructor of a window instance from the inspector? This would probably clear up the issue and others that people are having. Is there some way to do this that I have overlooked or is it currently impossible? Thanks
[quote=62621:@Jason King]Ok thanks for the verification Tim and the explanation Norman. Would you be able to tell me how some of the controls (say the Canvas) allow the Open event to occur?
[/quote]
Magic
Not quite but thats internal details
Not sure what you mean ?
Really depends on is this intended to be some kind of “control” - visual or not ?
If so then make your “controls” subclass “control” - if they have UI you might subclass RectControl or Canvas depending
Things like Timers and Noteplayers are great example of non-visual controls
And best of all “controls” get open events without you having to do ANYTHING
But a generic “class” on the window is going to behave this way
And there’s really no way around it as you can see
We can’t hook up events before there’s an instance and if the instance raises events when its constructed well
. that can’t work
But I can only give generic advice since I’m not sure what it is you’re trying to do
Would you be able to teach me these mystical arts?
There were two ideas here which is probably why it was confusing. If I add a timer as a property to the class than I can use AddHandler and call a method which raises the Open event, not a perfect solution but its only delayed by 1ms. The question I had was is there a way to pass values to the constructor of an object through the IDE inspector. For example a class called “Point” with a constructor:
Sub Constructor(X as integer, Y as integer)
mX=X
my=Y
end sub
In the inspector there would be a new heading called Constructor and it would have an X and Y value available to be used in the constructor, which could eliminate the need for an open event in some cases. But this is a separate issue I was asking about so I wouldn’t need an Open event from the constructor.
[quote=62622:@Norman Palardy]Really depends on is this intended to be some kind of “control” - visual or not ?
If so then make your “controls” subclass “control” - if they have UI you might subclass RectControl or Canvas depending
Things like Timers and Noteplayers are great example of non-visual controls
And best of all “controls” get open events without you having to do ANYTHING
But a generic “class” on the window is going to behave this way
And there’s really no way around it as you can see
We can’t hook up events before there’s an instance and if the instance raises events when its constructed well
. that can’t work
But I can only give generic advice since I’m not sure what it is you’re trying to do[/quote]
The classes I’m making are for a physics simulator so although they have a visual component they will be rendered with OpenGL or a canvas and not as a control on a window. I need the Open event so that I can initiate some of the properties, like position or velocity, for each one separately, although I will probably redesign since it’s not possible. I hope that makes sense? Thanks
Sounds like you just need your topmost class to have its Super as Control.
Norman, why does it work with a subclass, but not with a window instance? Eg., if Class1 has an Event Definition, Open, which it calls in the Constructor, and Class2 has a Super of Class1 and an Event Handler for Open, when you say “new Class2”, the code in the Open event handler runs. But if you drag an instance of Class1 to the window, even though the IDE allows you to add the event handler, the code doesn’t run. That difference in operation is what I referred to as a possible bug.
If it is documented that way, is it a bug?
[quote=62623:@Jason King]Would you be able to teach me these mystical arts?
[/quote]
No - this is built right into the runtime - you can’t achieve this with just Xojo code.
[quote=62623:@Jason King]WouldThere were two ideas here which is probably why it was confusing. If I add a timer as a property to the class than I can use AddHandler and call a method which raises the Open event, not a perfect solution but its only delayed by 1ms. The question I had was is there a way to pass values to the constructor of an object through the IDE inspector. For example a class called “Point” with a constructor:
Sub Constructor(X as integer, Y as integer)
mX=X
my=Y
end sub
In the inspector there would be a new heading called Constructor and it would have an X and Y value available to be used in the constructor, which could eliminate the need for an open event in some cases. But this is a separate issue I was asking about so I wouldn’t need an Open event from the constructor.
[/quote]
Ah. I see.
Doubtful.
You can set initial values with the “Inspector Behaviour” though
I would just not put them on the window and instead add properties to the window and then populate the window properties in the windows open event
There seems to be no advantage to having them on the layout
I’ve struggled with similar issues too. I think it could be the order of the methods/events which pose a problem here. This is the order:
- Constructors of subclassed control instances
- Window constructor
- Open events of controls (built-in control instances and subclassed control instances)
- Window open event
In addition the order of the controls is important. I suspect it is the order in which the controls have been added to the window - but I’m not sure and I’ve never used that fact in my code. So controls should not talk to each other in their constructors (do that in the window constructor), the same applies of course for the open events (do that in the open event of the window).
If the class is only used on window instances, I’d go with Norman’s suggestion and make your classes subclasses of Control - it’ll solve your problem nicely.
[quote=62652:@Eli Ott]I’ve struggled with similar issues too. I think it could be the order of the methods/events which pose a problem here. This is the order:
- Constructors of subclassed control instances
- Window constructor
- Open events of controls (built-in control instances and subclassed control instances)
- Window open event
In addition the order of the controls is important. I suspect it is the order in which the controls have been added to the window - but I’m not sure and I’ve never used that fact in my code. So controls should not talk to each other in their constructors (do that in the window constructor), the same applies of course for the open events (do that in the open event of the window).
If the class is only used on window instances, I’d go with Norman’s suggestion and make your classes subclasses of Control - it’ll solve your problem nicely.[/quote]
If you look at the code I posted and consider that each control is added one after the other you can see why controls on layouts will have issues if you try to refer to another control that has not been created. And since the construction of the control eventually raises the open event you can also see that referring to another control that may not yet be created will also be problematic.
In general if you need to set up the value of one control based on the value of another do it in the windows open event as all controls do exist then.