Flex custom components, events and scope - apache-flex

I'm starting to give up on the Flex forums so I'l re-post here and see how things go. Long time lurker, first time poster ;-)
I'm trapping keyboard events on the stage and dispatching custom events through a framework (Mate, though I don't know that this is an important issue), but I'm pretty confused by the scope. The structure is:
--application (traps keyboard events and dispatches custom event
-- mainPanel (receives dispatched events but mainCalendar (a child element)
is null on debugging. Obviously if I try to call a public method on
mainCalendar it errors out, even though it's a child of mainPanel.
However, mainCalendar is NOT null IF I use
FlexGlobals.topLevelApplication.mainPanel.mainCalendar.
Outerdocument and parentDocument do not expose mainCalendar either, BTW
-- mainCalendar (a custom component inside mainPanel with public methods.
Creation policy is 'all' and it's visible and exists long before I
trap any keystrokes at the top level)
Could someone take a minute and explain why the mainCalendar is out of scope when mainPanel receives a custom event, even though mainCalendar is a child of mainPanel. Is there a better way to manage the events so I don't have to always address the component via the topLevelApplication?
Thanks

(creating answer so this question could be marked as answered)
Usually, when reference to component is null and it should not, this means component isn't created yet. This might have place before application initialize event or if component's parent isn't visible and not validated.

Related

Qt: DefaultContextMenu vs CustomContextMenu

What's the difference between setting ContextMenuPolicy to DefaultContextMenu or CustomContextMenu? From what I can tell, they're the same things? Either way, you get to create a custom context menu if needed.
They are certainly not the same.
While they both could create a custom menu, their behavior is quite different. Consider the QWidget documentation:
The default value of this property is Qt::DefaultContextMenu, which means the contextMenuEvent() handler is called.
This means that you need to specifically override contextMenuEvent() in order to eventually show the context menu. This usually means that subclassing is required and only the widget will handle that event (which could also be ignored) and possibly its menu.
Note that overriding contextMenuEvent() could be done also for special cases of the event management, from the simplest one (accepting it, to avoid propagation to the parent) to more complex situations that need to set up some aspects before letting the default implementation to handle the event as usual.
With Qt::CustomContextMenu, the signal customContextMenuRequested() is emitted.
This means that any object can connect to that signal (and potentially more than once), even a completely unrelated one, and eventually do something from there. This also means that there is absolutely no access to the event, which will always be considered as accepted.

How do I propagate a mousePressEvent() to a group of QGraphicsItems?

I'm writing a program that uses the Qt Graphics View framework. I have subclassed QGraphicsItem to a class that includes other QGraphicsItem (or other subclasses of it). This class is the parent of the included QGraphicsItem; the idea is to work with composite objects.
From the docs it seems to be a conflict in what I try to achieve:
Calling ignore() in mousePressEvent will make my object unmovable. I want to move it.
Calling accept() in mousePressEvent will prevent the event from being propagated to the child object. Some of the child objects should react to mouse events.
How can I make this work?
I think your interpretation of the documentation is incorrect.
Calling ignore() in mousePressEvent will make my object unmovable.
I don't believe that is true. To me it looks like calling ignore() is like the object saying "I have assessed this event. I have taken all actions I want to in response to this event. I have also decided it was not intended for me, so I will now pass it on to the next object underneath me". I can't find anything which suggests the ignore event will unset the QGraphicsItem::ItemIsMovable flag (which is what decides if the QGraphicsItem is movable or not).
I don't see why you couldn't make your object move and ignore() the event, but I would advise that this is not a sensible approach (in most instances: obviously you may have cause for it).
Calling accept() in mousePressEvent will prevent the event from being propagated to the child object.
I believe this is true, but the parent can still modify its children. My understanding is calling accept() is like the object saying "I have assessed this event. I have taken all actions I want to in response to this event (which may include modifying my children). I have also decided that the event was intended for me, so I will not be passing the event on".
In your parent QGraphicsItem, you might try to
MyObject::mousePressEvent ( QGraphicsSceneMouseEvent * event )
{
QGraphicsItem::mousePressEvent(event);
event->ignore();
}
This would allow normal processing of the mouse event (i.e. make your object moveable), but then ignoring it so that it is propagated.
The logic would need to be more robust, though, because there is a high risk of side effects if a parent and child respond to the same mouse event.
Send QCoreApplication::postEvent(child, mouseEvent) to child objects.

Flex Cairngorm 3 Presentation Model Initializations

ok so I have a TitleWindow that I open up... and I have 6 states defined. I am using the Presentation model pattern for all of my views. I have discovered a frustrating nuance. When I tell my window to go to XXX state, the controls have to initialize since the states in flex use lazy loading. so... my PM code that says myTextArea.text bombs out and say "cannot access..." so as a work around, I made some creationComplete events on my controls to register the control with the PM. So when the state changes, the textarea finally initializes and on creationComplete calls PM.registerTextArea() which sets a reference to it. then in that function I run my code... myTextArea.text.. etc.
This seems like such a ugly hack that I hate it. Is there any way to wait until the entire state in created then call code on the PM? I have tried enterstate... but this event seems to fire before the state controls are ready.
I tried to add a comment, but I guess editing is the only way I can do this...
to everyone: thanks for the great feedback. I am doing something slightly off straight PM. Every view has a viewController (as I call them). Its kinda my own hybrid of a delegate / dataprovider. But this is moot. It's the flex component lifecycle when dealing with states that is the pain. if you change state.. there is no event to say "all my components in this state are ready". only event to say "we changed state". so my code that fires on state change is trying to talk to components that aren't ready yet. So from what I see, there seems to be no design pattern or perfect way to ensure that all components are created in a state unless using creationComplete on every component in the state to register it is ready... if you don't, you get a race condition. Regardless of frameworks or design patterns, this seems to be a root issue.
The textarea is an easy PM fix.. just bind it to the pm value. But there are other times I can't.
Specifically, I am trying to attach video to a display once I get to that state. This is done via addchild. regardless of where I do it.. I need to know that the videoDisplay is done loading before I call addchild. I even tried currentStateChange event since docs say that fires last... but alas.. the components in the state are still initializing. So it seems that creationComplete is my only option. Maybe the only sane way to keep to clean code is to create the entire thing (videodisplay and video) using as once the state is entered. I just hoped the flex framework had events to ehlp me here rather than buiilding everything on the fly in as.
Since your PM has a reference to a visual component (myTextArea), this isn't a completely pure form of a presentation model. It appears to be more of a supervising presenter / controller type of setup.
That being said, the way I would fix your problem would be to use a complete presenter outright ( no knowlege of the view at all ) or use a complete controller ( view implements an interface through which the controller communicates ). The advantage of using a presenter in Flex is that you can create a bindable value such as text or selectedItem, and the view will bind to that variable whenever it comes online so the issues dealing with the lifecycle of Flex components go away.

In Flex/Actionscript, how do I ensure that events all travel down one object tree, regardless of target?

I'm still working on my zoomable node-graph project. I'm currently having problems with what I know must be relatively easy, but have been unable to find a solution to:
I have numerous objects, many of them are stored within other objects (and overlap in physical space). As I zoom into an object, it begins to fade away. At the moment it begins to fade, I load in the child object (or create a child object if one doesn't exist). I want to turn off the parent object's ability to respond to most events. The exception is the scroll wheel, which needs to be sent to both objects simultaneously so that the parent can continue to fade out as I zoom farther in. Try as I might, I can't find a way to tell Flex "hey, for right now dispatch these types of events ONLY to this object." I either end up with event dispatch stack overflows from trying to manually redirect the events, or I get events that don't activate at the correct time or on the correct object. What can I do?
I want to turn off the parent object's
ability to respond to most events.
You can't turn off an objects ability to respond to events.
You can write code to remove all event listeners inside that object; although I suspect this will be a manual process.
You can remove that object from the display list so its event listeners won't trigger on events in their capture or bubbling phases. If this object has children that you want to display this won't work.
You may be able to work something out where the 'child' object calls stopPropogation() and/or stopImmediatePropogation() in it's own event listeners. I believe this could prevent the handlers from firing in the parent, but it may depend how your listeners are set up. I do not believe this will have an effect if you are listening in the capture phrase.
You may be able to write "aware" event handlers that basically say:
if(SomeConditionTrue){ return; }
I'm running out if ideas. But, I'm pretty sure there is no way to universally say "Don't let this component respond to events"

Access component id of one mxml from another

I have two mxml files. one is main that is application tag mxml file and another is my mxml component file.
I have a viewstack in my main mxml whose id is, say, "mainViewStack".
Now I want to set selectedChild property of "mainViewStack" from my mxml component file.
But I m getting error:
Error #1009: Cannot access a property or method of a null object reference.
on accessing mainObj.mainViewStack.selectedChild.id where mainObj is the object of main mxml file.
Please help me out.
Thank u.
My guess is that you're trying to access the child before it's created. But that's hard to tell without the code.
Try waiting until the FlexEvent.CREATION_COMPLETE event on the application to access the selected child.
This issue is referred to as "deferred instantiation" and is a product of the Flex Component Lifecycle. If you want an extremely thorough explanation of this concept, this white paper is probably the best I have read.
Essentially Flex creates components as they are needed. Each component has a lifecycle that takes it through stages:
Construction
Addition
Initialization
Invalidation
Validation
Update
Removal
A sub-component isn't going to be accessible until it has passed through the initialization phase. This is the point at which a Flex component will dispatch its CREATION_COMPLETE event, letting you (and the framework) know that it is ready for interaction. Prior to this event, you are going to receive null reference errors when attempting to access the component or its children.
ViewStacks compound this by default by not initializing sub-components until they are called for display. The creationPolicy property of a ViewStack, by default, is set to auto. There are several options for this property, including all. Be aware, however, that this can potentially present severe performance issues, as all of the components inside the stack are going to be initialized immediately regardless of whether or not the user actually even looks at the component.
In your specific case this isn't the problem. The component that contains the view stack hasn't been completely initialized. You need to set the child of the ViewStack in a CREATION_COMPLETE event handler.
or you can give "creationPolicy=all" because Flex only creates the first visible child from the viewstack
You can use this code in your MXML component to change application's ViewStack selected child from other MXML component. However it is not a good practice.
FlexGlobals.topLevelApplication.mainViewStack.selectedChild = FlexGlobals.topLevelApplication.childId
You can use static event dispatcher to dispatch an event from one view and listen that event in an other view.

Resources