I have created a custom component that I am using, more conveniently, as a SkinnablePopUpContainer and I want to use the same function that calls and receives data from it for several Buttons in the UI. What is the best way to achieve this without having to create a new function for each button?
<fx:Script>
<![CDATA[
import spark.events.PopUpEvent;
protected function button1_clickHandler(event:MouseEvent):void
{
popup.addEventListener(PopUpEvent.CLOSE, onPopUpEventClose1, false, 0, true);
popup.open(this);
}
private function onPopUpEventClose1(event:PopUpEvent):void {
popup.removeEventListener(PopUpEvent.CLOSE, onPopUpEventClose1);
trace(event.commit);
trace(event.data);
button1.label=event.data;
}
protected function button2_clickHandler(event:MouseEvent):void
{
popup.addEventListener(PopUpEvent.CLOSE, onPopUpEventClose2, false, 0, true);
popup.open(this);
}
private function onPopUpEventClose2(event:PopUpEvent):void {
popup.removeEventListener(PopUpEvent.CLOSE, onPopUpEventClose2);
trace(event.commit);
trace(event.data);
button2.label=event.data;
}
]]>
</fx:Script>
<s:Button id="button1" x="102" y="103" label="Button 1 Numbers"
click="button1_clickHandler(event)"/>
<s:Button id="button2" x="102" y="200" label="Button 2 Numbers"
click="button2_clickHandler(event)"/>
You can see how I would rather have one set of functions that can handle all of this rather than manually coding each function.
Is there a way to get the id of the component that calls the function? What's the best way to solve this?
EDIT: SOLUTION
I have been able to replace all of that code with the trimmer following:
private var buttonPick:Button;
public function button_clickHandler(button:Button):void
{
switch (button) {
case button1: popup.addEventListener(PopUpEvent.CLOSE, onPopUpEventClose, false, 0, true);
popup.open(button);
break;
case button2: popup.addEventListener(PopUpEvent.CLOSE, onPopUpEventClose, false, 0, true);
popup.open(button); break;
}
buttonPick = button;
}
private function onPopUpEventClose(event:PopUpEvent):void {
popup.removeEventListener(PopUpEvent.CLOSE, onPopUpEventClose);
trace(event.commit);
trace(event.data);
buttonPick.label=event.data;
}
and this as the mxml:
<s:HGroup click="button_clickHandler(event.target as Button)">
<s:Button id="button1" x="102" y="103" label="Button 1 Numbers"
/>
<s:Button id="button2" x="102" y="200" label="Button 2 Numbers"
/>
</s:HGroup>
Thanks for the input and advice! And if there is a more efficient way to do it than with case statements, be sure to suggest it!
You should put those buttons into a common container and listen for clicks on that container. Then you can use Event#target to detect which element in the container was clicked.
Your buttons in a common container:
<s:Group click="button_clickHandler(event.target as Button)">
<s:Button id="button1" x="102" y="103" label="Button 1 Numbers" />
<s:Button id="button2" x="102" y="200" label="Button 2 Numbers" />
</s:Group>
The event handler:
protected function button_clickHandler(button:Button):void {
switch (button) {
case button1: trace('clicked button 1'); break;
case button2: trace('clicked button 2'); break;
default: trace('clicked somewhere else in the group'); break;
}
}
As you can see, I cast event.target to a Button class using the 'as' keyword. This way, if you click anything else than a Button, the 'button' argument will be 'null'.
Read the docs for Event.target and Event.currentTarget. In this case you want to use currentTarget. This article describes the differences between target and currentTarget.
Related
I am kinda new with datagrids and spark, and been wracking my brain to figure this out. I have a datagrid being loaded with an XMLList. One field is a numeric value that will be calculated times another field and that result be stored and displayed in the grid on the fly.
Example:
XML
<SampleTable>
<Row>
<Item>Item 1</Item>
<Quantity>10</Quantity>
<Price></Price>
<Cost></Cost>
</Row>
</SampleTable>
So a user would enter in the price, and the Cost would be updated in the grid with the Price * Quantity values, with the dataprovider being updated with the result when the form is saved.
Adding in the grid and the XML is already bound. I can get simple updates to the cells to work. I need help figuring out where to do a calculation. Only the price is editable, and when that cell changes value I want the Cost to be calculated.
Handlers for the editing session:
import spark.components.gridClasses.CellPosition;
import spark.events.GridEvent;
private var mouseDownRowIndex:int;
private var mouseDownColumnIndex:int;
protected function dataGrid_gridMouseDownHandler(event:GridEvent):void
{
mouseDownRowIndex = event.rowIndex;
mouseDownColumnIndex = event.columnIndex;
}
protected function dataGrid_gridMouseUpHandler(event:GridEvent):void
{
// Start a grid item editor if:
// - the rowIndex is valid
// - mouseUp is on the same cell and mouseDown
// - shift and ctrl keys are not down
// - cell is editable
// - an editor is not already running
// An editor may already be running if the cell was already
// selected and the data grid started the editor.
if (event.rowIndex >= 0 &&
event.rowIndex == mouseDownRowIndex &&
event.columnIndex == mouseDownColumnIndex &&
!(event.shiftKey || event.ctrlKey) &&
event.column.editable &&
!event.grid.dataGrid.itemEditorInstance)
{
event.grid.dataGrid.startItemEditorSession(event.rowIndex, event.columnIndex);
}
}
<s:DataGrid id="dgTest" x="10" y="68" width="900" editable="true" electionMode="singleCell" requestedRowCount="4" gridMouseDown="dataGrid_gridMouseDownHandler(event)" gridMouseUp="dataGrid_gridMouseUpHandler(event)">
<s:columns>
<s:ArrayList>
<s:GridColumn width="250" dataField="Item" headerText="Item" resizable="true" sortable="false" editable="false"></s:GridColumn>
<s:GridColumn width="160" dataField="Quantity" headerText="Quantity" resizable="false" sortable="false" editable="false"></s:GridColumn>
<s:GridColumn width="90" dataField="Price" headerText="Price" resizable="false" sortable="false" ></s:GridColumn>
<s:GridColumn width="90" dataField="Cost" headerText="Cost" resizable="false" sortable="false" editable="false"></s:GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid>
You should make your datasource Bindable.
So in code (AS), this would be:
[Bindable]
var myXMLList:XMLList;
I don't think it is possible to bind to an XMLList however. You should make use of an XMLListCollection instead.
It's still not clear to me if your want to save your data somewhere, or if you just want to visualize...
s:GridColumn has a property called "labelFunction". Maybe this is sufficient for your needs.
public function myLabelFunction(item:Object, column:DataGridColumn):String
{
var amount:Number = item.Quantiy;
var price:Number = item.Price;
return amount*price as String
}
In you example
<s:GridColumn width="90" dataField="Cost" headerText="Cost" resizable="false" sortable="false" editable="false"></s:GridColumn>
would be changed into
<s:GridColumn width="90" dataField="Cost" headerText="Cost" resizable="false" sortable="false" editable="false" labelFunction="myLabelFunction"></s:GridColumn>
Provided code is by no means complete. It serves as an example.
Good luck.
Got it working using an itemrenderer. It's ugly but works.
What I am having trouble with is moving this event to when the PercentComplete field is changed instead of the click event on this field. This is the timing I am having trouble with.
<s:GridColumn width="90" dataField="Extension" headerText="Extension" resizable="false" sortable="false" rendererIsEditable="true">
<s:itemRenderer>
<fx:Component>
<s:GridItemRenderer mouseDown="itemrenderer1_dataChangeHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.events.GridEvent;
protected function itemrenderer1_dataChangeHandler(event):void
{
if(data){
var data_field:String = ((parseFloat(data['PercentComplete'])/100)*parseFloat(data['Weight'])).toFixed(2).toString();
this.dataLabel.text = data_field;
data.Extension[0] = data_field;
}
}
]]>
</fx:Script>
<s:Label id="dataLabel" text="{data.Extension}" height="100%" width="100%" textAlign="left" verticalAlign="middle"/>
</s:GridItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:GridColumn>
The Datagrid is owner of the datasource, not the GridItemRenderer.
Therefore you should not use mouseDownEvents. (What will happen when to Tab trough your cells?). You might even consider moving this kind of business logic away from your view into your controller (or your model).
For your example, your really don't need a "fancy" GridItemRenderer. Everything has to be calculated outside of your datagrid.
The spark Datagrid has an event which is call "gridItemEditorSessionSave".
spark.components.DataGrid.gridItemEditorSessionSave
Dispatched after the data in item editor has been saved into the data
provider and the editor has been closed.
Event Type: spark.events.GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_SAVE
Language Version: 3.0
Player Version: Flash 10, AIR 2.5
Product Version: Flex 4.5
Personally I would implement a Bindable ValueObject and convert my XMLList in an IList implementation, for example and ArrayCollection, containing a set of those objects. Example follows:
[Bindable]
public class MyValueObject
{
public var percentComplete:Number;
public var weight:Number;
public function get extension():Number
{
return percentComplete*weight;
}
}
If you populate your datagrid with these ValueObjects, you can use a dumb view and even better, you can use any view you like without having to change your actual application. (Isn't that the purpose of OO Programming?)
This question is completely different than the first one though. I'm willing to provide answers, but you should do some research on your own.
Use Flex 4.5.1 and when add icons to the button is so curve effect of scaling.
Prompt how to make a proportional scaling icons?
<s:Button width="100%" height="50" label="Create new map" click="button3_clickHandler(event)"
fontSize="22" icon="#Embed('icons/001-folder.png')">
try to create custom skin for button and do the same in commitProperties
override protected function commitProperties():void
{
super.commitProperties();
if(iconDisplay){
iconDisplay.scaleMode = BitmapScaleMode.LETTERBOX;
}
}
try add creation complete handler and set btn.iconDisplay.scaleMode to BitmapScaleMode.LETTERBOX
protected function creationCompleteHandler(event:FlexEvent):void
{
btn.iconDisplay.scaleMode = BitmapScaleMode.LETTERBOX
}
<s:Button id="btn" creationComplete="creationCompleteHandler(event)" width="100%" height="50" label="Create new map" click="button3_clickHandler(event)"
fontSize="22" icon="#Embed('icons/001-folder.png')">
I have a small flex application.
<mx:Script>
<![CDATA[
import flash.events.Event;
// Event handler function to print a message
// describing the selected Button control.
private function printMessage(event:Event):void {
message.text += event.target.label + " pressed" + "\n";
}
]]>
</mx:Script>
<mx:Panel title="Button Control Example"
height="75%" width="75%" layout="horizontal"
paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10">
<mx:VBox>
<mx:Label width="100%" color="blue"
text="Select a Button control."/>
<!-- The button can contain an image, as in the "Button with Icon" button -->
<mx:Button id="iconButton" icon="#Embed('assets/mm-icon.png')" label="Button with Icon"
labelPlacement="right" color="#993300" click="printMessage(event);"/>
<!-- The size of the button and the label attributes can be customized -->
<mx:Button label="Customized Button" color="#993300" toggle="true" selected="true"
textAlign="left" fontStyle="italic" fontSize="13" width="{iconButton.width}"
click="printMessage(event);"/>
<!-- By default, the look and feel of the customized button is
similar to the Default Button. -->
<mx:Button label="Default Button" click="printMessage(event);"/>
</mx:VBox>
<mx:TextArea id="message" text="" editable="false" height="100%" width="100%"
color="#0000FF"/>
</mx:Panel>
What I want to achieve is, I want my user to pass the script as a parameter. so he has the flexibility to do anything with the buttons->like add event, hide the other buttons.
Something like this(below)
<param name="script" value="import flash.events.Event;\n private function printMessage(event:Event):void {\nmessage.text += event.target.label + " pressed" + "\n";\n}">
Thanks.
If I understood, what you want is simply create dynamic event and load it to some component, right? If so in did its very easy to implement.
Just create your own custom event (inherit from Event) or use the Event itself:
var event:Event = new Event("[Your event type here"],[bubbles?],[cancelable?]);
and then add listener to your wanted component to the same "event type".
If you need you can also dispatch this event from wanted component programmatically like this:
[you component].dispatchEvent(event);
but then you have to make sure this component extends EventDispatcher class.
Hope I helped.
Royee
I have a HGroup with some buttons inside which is my application's menu.
<s:HGroup id="nav">
<s:Button id="homeButton" label="Home" />
<s:Button id="showroomButton" label="Showroom" />
<s:Button label="Catalogue" />
<s:Button label="Offers" />
<s:Button label="My Account" />
<s:Button label="My Orders" />
</s:HGroup>
What I want is when I click for example the #homeButton to change it's state to "over", become disabled and reset all other buttons to the "up" state.
I've written this function
private function resetNavState():void {
for(var i:int = 0,ii:int = nav.numChildren-1;i<ii;i++) {
Button(nav.getChildAt(i)).mouseEnabled = true;
Button(nav.getChildAt(i)).skin.setCurrentState("up",true);
}
}
And then on the homeButton click handler for example i use
protected function homeButton_clickHandler(event:MouseEvent):void
{
resetNavState();
currentState = "home";
homeButton.skin.setCurrentState("over",true);
homeButton.mouseEnabled = false;
}
I resets the states of the #nav buttons but it doesn't change the state of the pressed button.
Any ideas?
Thanx in advance
You'll want to place your buttons in a in a <s:ButtonBar /> control rather than the HGroup.
I am creating a lot of dynamic flex components like RadioButton, Combo Box, CheckBox.
if(type=="mx.controls.CheckBox"){
//if(rep.currentIndex<5){
for each(j in x){
k=createNewInstanceOfClass(rep.currentItem.type);
k.id="radioGroup"+rep.currentItem;
k.label=j.linkname;
k.data=j.linkname;
linkPanel[rep.currentIndex].addChild(DisplayObject(k));
}
MXML
<mx:Panel layout="horizontal" id="linkPanel" title="Evaluation" fontWeight="bold" height="100%" backgroundColor="0xFFF7E6"
borderThicknessLeft="0" borderThicknessRight="0" cornerRadius="10" headerHeight="20" dropShadowEnabled="false" roundedBottomCorners="true" verticalScrollPolicy
="off" horizontalScrollPolicy="off" headerColors="[#ffffff,#ffffff]" width="100%">
<mx:Form>
<mx:FormItem paddingLeft="2" paddingTop="2" paddingBottom="2">
<mx:Repeater id="rep2" dataProvider="{sendToActionScript(rep.currentItem.link)}" />
</mx:FormItem>
</mx:Form>
</mx:Panel>
When i click on Submit finally i need to get all the selected Values in each question. All the components are dynamically created at runtime.
You can list the children of linkPanel with getChildren()
when looping through them, read the "selected" property
public function test():void {
for each ( var obj:Object in linkPanel.getChildren()) {
if( obj is RadioButton) {
Alert.show( (obj as RadioButton).selected.toString());
}
}
}
If you are creating a list of radio buttons belonging to a group, look into "selectedValue" for this group
<mx:RadioButtonGroup id="rbg" />
<mx:RadioButton id="answer1" group="{rbg}" label="Answer 1" />
public function test():void {
Alert.show( rbg.selectedValue.toString())
}