I am writing an custom component in Flex 3.2 that extends the panel component. After a user performs a certain action I would like to hide the main content area in the Panel component, as well as the Control Bar if one is specified. Any ideas on how to do this? controlBar.visible does not seem to hide the control bar, and I don't know of another easy way of accessing the main content area besides iterating through all the children of the main panel, and I would like to avoid that if possible. Thanks
Couldn't you set one main container, whether a HBox or VBox etc... inside your Panel that would contain all the children, then you could toggle this container visibility depending on the user's action.
As for the ControlBar , you should be able to change its visibility value...
The reason you can't seem to hide the controlbar, is because you are only setting it's visible property - it's still taking up it's space. So, to truly "hide" it, do this:
myControlBar.includeInLayout = false;
Also, to hide all you children, only requires a simple loop:
for each (var oChild:DisplayObject in idPanel.getChildren()) {
oChild.visible = false;
}
So, the entire application would look like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
private function doit(): void {
idControl.visible = false;
idControl.includeInLayout = false;
for each (var oChild:DisplayObject in idPanel.getChildren()) {
oChild.visible = false;
}
}
]]>
</mx:Script>
<mx:Button x="10" y="10" label="Button" click="doit()"/>
<mx:Panel x="83" y="10" width="250" height="200" layout="absolute" id="idPanel">
<mx:CheckBox x="10" y="10" label="Checkbox"/>
<mx:DateField x="10" y="40"/>
<mx:ControlBar id="idControl">
</mx:ControlBar>
</mx:Panel>
</mx:Application>
Hope that helps!
Related
I am working on a Flex TabbedViewNavigatorApplication with three tabs (ViewNavigator elements). I would like to switch from one ViewNavigator to another based upon a user action (via ActionScript code).
I know that switching between Views uses pushView and popView, but I'm working with ViewNavigators, and my searching revealed nothing useful.
I'm trying to switch from Tab2 to Tab1 when an event occurs. In this case, Tab2 contains a list, and when the user makes a selection, I want to jump back to Tab1.
<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="onAppReady(event)">
<s:ViewNavigator label="Tab1" width="100%" height="100%" firstView="views.TabOneView"/>
<s:ViewNavigator label="Tab2" width="100%" height="100%" firstView="views.TabTwoView"/>
<s:ViewNavigator label="Tab3" width="100%" height="100%" firstView="views.TabThreeView"/>
</s:TabbedViewNavigatorApplication>
Thanks for your help!
I use the following line of ActionScript to switch from one ViewNavigator to another based on a user action:
TabbedViewNavigator(navigator.parentNavigator).selectedIndex = 1;
It worked like a charm and seems simpler than bubbling events.
This class is strangely undocumented. I have not tried this myself, but from searching online, this is what I found which corroborates with what the rest of the network does.
What you need to do is bubble an event to the TabbedViewNavigatorApplication and from there change the selectedIndex property to whichever tab you need to change to. For example:
<s:TabbedViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="onCreationComplete()">
<fx:Script>
<![CDATA[
private function onCreationComplete():void
{
this.addEventListener('someEvent', someHandler);
}
private function someHandler(e:Event):void
{
this.selectedIndex = 0; // or whatever index you want.
}
]]>
</fx:Script>
<s:ViewNavigator label="Tab1" width="100%" height="100%" firstView="views.TabOneView"/>
<s:ViewNavigator label="Tab2" width="100%" height="100%" firstView="views.TabTwoView"/>
<s:ViewNavigator label="Tab3" width="100%" height="100%" firstView="views.TabThreeView"/>
</s:TabbedViewNavigatorApplication>
You just need to dispatch a bubbling event from within your children. You could event create a custom event that holds data about which tab to switch to.
I have an AIR application. It should be moved around the screen with the mouse. In order to achieve this I use the event:
this.stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, true,-2);
It should be activated with the lowest priority compared to inserted elements for example those that should be scrolled, clicked, etc.
I tried the solution shown below with the event priority set to -1 because there might happen 2 different events and my moving application event should be the last one to be serviced or shouldn't be serviced at all.
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="200"
height="200"
applicationComplete="init()">
<fx:Script>
<![CDATA[
import mx.core.Window;
import mx.events.ScrollEvent;
private function init():void {
this.stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, true,-2);
}
private function onMouseDown(event:MouseEvent):void {
trace("clicked on stage "+event.currentTarget.toString());
if(event.currentTarget == stage){
trace("catched stage target");
this.nativeWindow.startMove();
event.stopImmediatePropagation();
}
}
function scrolledCanvasHandler(event:ScrollEvent){
trace("clicked on canvas "+event.currentTarget.toString());
event.stopPropagation();
}
]]>
</fx:Script>
<mx:Canvas x="29" y="34" width="80%" height="80%" backgroundColor="#343434" scroll="scrolledCanvasHandler(event)">
<mx:Label x="25" y="77" text="moving window, moving window"
fontSize="18" color="#FFFFFF" fontWeight="bold"/>
</mx:Canvas>
</s:WindowedApplication>
As you will notice the
event.stopPropagation();
doesn't work.
Perhaps my solution isn't the best suited to achieve this. Are there better solutions?
Chris
that's what i did in an app of mine:
<s:HGroup id="appTitleBar"
width="100%" height="35"
styleName="titleBar"
mouseDown="nativeWindow.startMove();"
doubleClickEnabled="true"
doubleClick="nativeWindow.minimize();"
contentBackgroundColor="#313131"/>
click (+drag) on this HGroup will drag the window. duobleclick will minimize it.
edit
don't make your whole app draggable this will only confuse the user.
and btw priority should be positive not negative - but also don't mess with this. not expected behavior for anyone.
Beginner Question:
I am using the IFrame Component for Flex in Flex 4. The code below works when it is put at the top of the scrolling area. However, if I put it where it below the viewable area it will not render. I am a complete beginner to Flex. The interesting thing is when I resize the window while the HBox is in view, the Iframe will load. But scrolling to it will not. Below is my code. I have made sure everything is visible=true but it seems like I need to add a listener or somehow trick it to think that the window has been resized to get it to render. Anyone with an idea how to fix this? Thanks!
<mx:HBox visible="true" backgroundColor="#cccccc" id="facebookhbox" width="100%" height="100" horizontalAlign="center" verticalAlign="middle" verticalGap="0" verticalScrollPolicy="off">
<mx:Canvas id="facebookcanvas" visible="true" x="0" y="0" width="650" height="80">
<flexiframe:IFrame visible="true" y="0" x="0" id="facebookIFrame" source="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.examplelink.com&layout=standard&show_faces=true&width=450&action=like&colorscheme=light&height=80" width="450" height="80"/>
</mx:Canvas>
</mx:HBox>
No experience with the Flex IFrame here just FYI but in generic terms you can invalidate the size of the component or invalidate the display list then call validate now in order to force the LayoutManager to recalculate the sizes of the element and it's children (or simply draw in the case of invalidating the display list):
The difficult part I see here is figuring out when exactly you want that to happen (that is capturing some sort of event from the scrollbar). For test purposes you can just create a button and in it's click handler do the following:
facebookIFrame.invalidateSize();
facebookIFrame.invalidateDisplayList();
facebookIFrame.validateNow();
If this works out then you just need to find the appropriate event from the Scroller or Canvas that tells you when scrolling is occuring (at worst you could capture mouse down mark a flag then capture mouseMove and if the flag is set then run the code to invalidate/re-validate). Basically how the layout/drawing works is that the UIComponents have flags that let it know when it needs to recalculate the size of something or redraw it, this way everything isn't always redrawn only those components that require it. In this case it seems the FacebookIFrame isn't getting invalidated at some point when it should. Let me know if I can help anymore or if this doesn't work out.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
height="100%"
width="100%"
xmlns:code="http://code.google.com/p/flex-iframe/"
mouseDown="application1_mouseDownHandler(event)"
mouseUp="application1_mouseUpHandler(event)"
mouseMove="application1_mouseMoveHandler(event)">
<mx:Script>
<![CDATA[
var isMouseDown:Boolean;
protected function button1_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
facebookIFrame.invalidateSize();
facebookIFrame.invalidateDisplayList();
facebookIFrame.validateNow();
}
protected function application1_mouseDownHandler(event:MouseEvent):void
{
isMouseDown = true;
}
protected function application1_mouseUpHandler(event:MouseEvent):void
{
isMouseDown = false;
}
protected function application1_mouseMoveHandler(event:MouseEvent):void
{
if(isMouseDown)
{
facebookIFrame.invalidateSize();
facebookIFrame.invalidateDisplayList();
facebookIFrame.validateNow();
}
}
]]>
</mx:Script>
<mx:Spacer height="1000"/>
<mx:Button label="Test Invalidation"
click="button1_clickHandler(event)"/>
<mx:HBox visible="true" backgroundColor="#cccccc" id="facebookhbox" width="100%" height="80" horizontalAlign="center" verticalAlign="middle" verticalGap="0" verticalScrollPolicy="off">
<mx:Canvas id="facebookcanvas" visible="true" x="0" y="0" width="650" height="80">
<code:IFrame visible="true" y="0" x="0" id="facebookIFrame" source="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.examplelink.com&layout=standard&show_faces=true&width=450&action=like&colorscheme=light&height=80" width="450" height="80"/>
</mx:Canvas>
</mx:HBox>
</mx:Application>
Updated to include a full application showing the example working, this is by no means a good way of doing things, this is due to a bug in the IFrame code that should be fixed (though I'm not sure how or where the bug exists something should be causing it to invalidate appropriately where it is not).
Shaun
I'm trying to capture key events in a mx:Image and I can't get it to work.
<?xml version="1.0" encoding="utf-8" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" />
<mx:Canvas width="100%" height="100%">
<mx:Label id="lab" x="50" y="20" text="Nothing"/>
<mx:Image x="50" y="50" source="#Embed('image.png')" keyDown="lab.text='Something';"/>
</mx:Canvas>
</mx:Application>
When I press a key when the mouse is over the image I expect the label text to change to "Something", but nothing happens. I've done all sorts of combination of enabled and putting the keyDown on the canvas and the label as well.
What am I missing?
The issue is one of focus. Key down events are only generated within a component when that component (or one of its descendants) has focus. In order for an Image to receive focus, you must set focusEnabled to true. This, however, requires that the user tab to give the Image focus, since clicking on an Image does not convey focus, much less mousing over it.
If you want to listen for the key down event when the user's mouse is over the Image, you can manually assign focus to the Image when the user moves their mouse over it.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
import mx.managers.IFocusManagerComponent;
private var oldFocus:IFocusManagerComponent;
public function imageMouseOver(event:MouseEvent):void {
oldFocus = focusManager.getFocus();
var newFocus:UIComponent = event.target as UIComponent;
newFocus.setFocus();
}
private function imageMouseOut(event:MouseEvent):void {
if (oldFocus) {
oldFocus.setFocus();
}
}
]]>
</mx:Script>
<mx:Canvas width="100%" height="100%">
<mx:Label id="lab" x="50" y="20" text="Nothing"/>
<mx:Image x="50" y="50" source="#Embed('image.png')" mouseOver="imageMouseOver(event)" mouseOut="imageMouseOut(event)" keyDown="lab.text='Something';" focusEnabled="true"/>
</mx:Canvas>
</mx:Application>
Alternately, you can assign a key down listener to the stage when the user mouses over the Image, and remove it when the user mouses out.
Image derives from (a.k.a "is a") SWFLoader. You need to add listeners to the content of the loader, not the loader itself. See this question for details, Interact with SWF Loader
Is there an easy way to make a parent container (eg Group) resize when it's children resize?
Below is a little example app. When I put the 200x200 'food' in the 'stomach' the stomach & it's containing 100x100 'body' should resize to contain the food.
Any ideas?
(from this gist http://gist.github.com/301292)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="1024"
minHeight="768"
creationComplete="application1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_creationCompleteHandler(event:FlexEvent):void {
}
protected function eatFoodTrigger_clickHandler(event:MouseEvent):void {
var food:Border = new Border();
food.setStyle('backgroundColor', 0x15DCA9);
food.width = 200;
food.height = 200;
stomach.addElement(food);
}
]]>
</fx:Script>
<s:Group verticalCenter="0" horizontalCenter="0">
<s:layout>
<s:VerticalLayout horizontalAlign="center" />
</s:layout>
<s:Label fontSize="24" text="The 100x100 pink/brown body has a stomach inside it.
Press eat and the stomach gets 200x200 'food' added to it.
I want the body and the stomach to expand to fit the food." width="200">
</s:Label>
<s:Border id="body"
backgroundColor="0x333333"
minWidth="100"
minHeight="100"
borderColor="0xFF4466"
borderWeight="5">
<s:Group id="stomach">
</s:Group>
</s:Border>
<s:Button id="eatFoodTrigger" click="eatFoodTrigger_clickHandler(event)" label="eat" />
</s:Group>
</s:Application>
Ok so it was a bug in the flex 4 sdk, and it's been fixed. Awesome.
From: http://forums.adobe.com/thread/575252
Your example works for me in a recent
build. Perhaps it was a bug in an old
build. Try one of the new nightly
builds:
http://opensource.adobe.com/wiki/display/flexsdk/DownloadFlex4
-Ryan
Obviously, this is a bit too late, but you could have overriden the addElementAt-method and added some functionality for resizing there. Below, you can see how addElementAdd() should/could be overridden.
//This would be placed in a custom component that extends Group. Your stomach would be this component.
override public function addElementAt(element:IVisualElement, index:int):IVisualElement
{
super.addElementAt(element, index);
ChangeWatcher.watch(element, "width", function():void{ resizeHandler(element) });
ChangeWatcher.watch(element, "height", function():void{ resizeHandler(element) });
}
private function resizeHandler(el:IVisualElement):void
{
var element:DisplayObject = el as DisplayObject;
//Rest of the resizing code.
}
I know this worked for flex3 and Canvas, so it should also work with flex4 and Group.