I have a list of buttons:
agreeButton
disagreeButton
container.clickButton1
container.clickButton2
Container is another movieclip and inside of it are the last 2 buttons.
How can I put it in array and have all the same listeners applied to each of them?
var buttonArray:Array = new Array("agreeButton", "disagreeButton", "container.clickButton1", "container.clickButton2");
for (var i:int=0; i<buttonArray.length; i++) {
this[buttonArray[i]].addEventListener(MouseEvent.ROLL_OVER, mouseRollOver);
this[buttonArray[i]].addEventListener(MouseEvent.ROLL_OUT, mouseRollOut);
this[buttonArray[i]].addEventListener(MouseEvent.CLICK, mouseClick);
}
Keep a reference to the buttons and add them to an array.
var agreeButton:Button = new Button();
var disagreeButton:Button = new Button();
//... Code that will add the above instantiated buttons to the canvas
var buttonArray:Array = new Array(agreeButton, disagreeButton);
for (var i:int = 0; i < buttonArray.length; i++) {
buttonArray[i].addEventListener(MouseEvent.CLICK, mouseClick);
}
private function mouseClick(event:MouseEvent):void {
Alert.show("Boom!");
}
I would make a button class that is extended by each of these buttons. In the button class you add eventListeners.
Example:
forgive me if there are things wrong with this, I haven't coded in AS3 for a while.
class MyButton extends Button
{
public function MyButton()
{
this.addEventListener(MouseEvent.ROLL_OVER, mouseRollOver);
this.addEventListener(MouseEvent.ROLL_OUT, mouseRollOut);
this.addEventListener(MouseEvent.CLICK, mouseClick);
}
//... Add mouseRollOver, mouseRollOut, mouseClick methods
}
Your Individual Buttons
class DisagreeButton extends MyButton
{
public function DisagreeButton()
{
}
}
class AgreeButton extends MyButton
{
public function AgreeButton()
{
}
}
Once you instantiate the buttons all the event listeners will be applied to each.
Related
I'm trying to implement an Android style side menu and I'm having an issue implementing the rounded icon on top and labels below it before the sideCommands are added.
How do I implement this please?
You can use Toolbar API which allows you to add components to the Sidemenu.
Have a look at Flickr demo.
Instead of using tool.addCommandToSideMenu(Command) you should use tool.addComponentToSideMenu(yourComponent, CommandToPerform)
Example:
#Override
protected void beforeMain(Form f) {
//Store your commands before setting toolbar
List<Command> cmds = new ArrayList();
for (int i = 0; i < f.getCommandCount(); i++) {
cmds.add(f.getCommand(i));
}
Toolbar toolbar = new Toolbar();
f.setToolBar(toolbar);
Label lblTitle = new Label("My Form", "Title");
lblTitle.setEndsWith3Points(false);
toolbar.setTitleComponent(lblTitle);
// Use your stored commands after setting toolbar
for (Command cmd : cmds) {
toolbar.addCommandToSideMenu(cmd);
}
Container CustomContainer = ...
toolbar.addComponentToSideMenu(CustomContainer, new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
//What CustomContainer should do (if any)
}
});
f.revalidate();
}
in the tutorial http://docs.oracle.com/javafx/2/ui_controls/tree-view.htm it explain how to create a TreeView with ContextMenu or CheckBox.
but is it possible to have both of them?
when I first copy-paste the code, I learned that I can have only one setCellFactory since they overwrite each other.
// the following two setCellFactory are copied from the tutorial
// this create TreeCell with ContextMenu
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> p) {
return new TextFieldTreeCellImpl();
//the class TextFieldTreeCellImp is a TreeCell with ContextMenu
}
});
// this create TreeCell with CheckBox
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
then i tried substituting TreeCell with CheckBoxTreeCell
//class TextFieldTreeCellImpl extends TreeCell<String> {
class TextFieldTreeCellImpl extends CheckBoxTreeCell<String> {
...
//TreeItem newTag = new TreeItem<String>("New tag");
CheckBoxTreeItem newTag = new CheckBoxTreeItem<String>("New tag");
but the checkbox didn't appear. it's still a normal treeview.
I think the fastest way to get a TreeView with CheckBoxes and a ContextMenu is adding the ContextMenu within the factory callback:
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> param) {
TreeCell<String> cell = CheckBoxTreeCell.<String>forTreeView().call(param);
ContextMenu menu = new ContextMenu();
MenuItem item1 = new MenuItem("Item 1");
MenuItem item2 = new MenuItem("Item 2");
EventHandler<ActionEvent> eh = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Item '" + event.getSource() +
"' of cell '" + cell + "' was clicked.");
}
};
item1.setOnAction(eh);
item2.setOnAction(eh);
menu.getItems().add(item1);
menu.getItems().add(item2);
cell.setContextMenu(menu);
return cell;
}
});
I call the usual TreeCell factory for the CheckBoxes. However, before returning the cell I add the ContextMenu.
Using the EventHandler, you can specify the clicking behaviour of the respective item.
If you have further questions or this is not a satisfying solution of you problem, feel free to contact me.
When I try this it doesn't remove the right button. Could you please point me in the right direction in finding what's wrong.
private var myArray:Array = [];
private var myButton:Button;
public function addButton():void {
var i:uint = myArray.length;
myButton = new Button();
myButton.label = "New Button"+ String(i);
myButton.id= "myButton" + String(i);
myGroup.addElement(myButton);
myArray.push(myGroup.addElement(myButton));
myButton.addEventListener(MouseEvent.CLICK, removeButton);
}
public function removeButton(event:MouseEvent):void {
//myGroup.removeElement(myArray.splice(2,1)); donĀ“t work
//myGroup.removeElement(myArray.pop()); remove the last one
}
Try following. It will work and remove the button which is pressed.
public function removeButton(event:MouseEvent):void
{
myGroup.removeElementAt(myArray.indexOf(event.currentTarget));
myArray.splice(myArray.indexOf(event.currentTarget), 1);
}
So I have an inventory with items and the array has the instance name of the items, which are movieclips. I want to make it so that all the items will have their button mode become true.
Everything works up to i.buttonMode = true. I get this:1119: Access of possibly undefined property buttonMode through a reference with static type String. But if I use the instance name, something like Inv_1.buttonMode = true works.
So the main question is I guess, how can you iterate through an array and make each of the instance names into buttons?
(I also tried getChildByName.(i).buttonMode = true;) and that didn't work. :S
package {
import flash.display.*;
import flash.events.*;
public dynamic class Drag extends MovieClip {
var Inventory:Array = ["Inv_1", "Inv_2", "Inv_3", "Inv_4t", "Inv_5"];
public function Drag():void {
for (var i:String in Inventory){
i.buttonMode = true;
}
}
}
}
Your Inventory array is a collection of strings, not MovieClips.
If those are instance names of child display objects, implement getChildByName as a function, not dot notation.
Also note getChildByName returns DisplayObject, which does not define buttonMode. Cast the object as MovieClip or appropriate type.
package {
import flash.display.*;
import flash.events.*;
public dynamic class Drag extends MovieClip {
var Inventory:Array = ["Inv_1", "Inv_2", "Inv_3", "Inv_4t", "Inv_5"];
public function Drag():void {
for (var i:String in Inventory) {
MovieClip(getChildByName(i)).buttonMode = true;
}
}
}
}
you have created an array of strings, not movie clip instances.
declare your instance names and add them to a vector:
package
{
import flash.display.*;
import flash.events.*;
public dynamic class Drag extends MovieClip
{
private var Inv_1:MovieClip;
private var Inv_2:MovieClip;
private var Inv_3:MovieClip;
private var Inv_4:MovieClip;
private var Inv_5:MovieClip;
public function Drag():void
{
var Inventory:Vector.<MovieClip> = new <MovieClip>[Inv_1, Inv_2, Inv_3, Inv_4t, Inv_5];
for (var i:MovieClip in Inventory)
{
i.buttonMode = true;
}
}
}
}
I wanted to setup an array of movieclip buttons to navigate across my timeline via labels, this is where it went pear shaped.
Having spent three days reading and attempting most online solutions I couldn't find a method which worked 100% without failing in some way or another.
I've had some joy with the method below having seen a blog entry covering different ways to call frames etc and which highlighted the bugbear below :
clipArray[i].mouseChildren = false; //Hidden bugbear
I've added the full code below so hopefully it may help anyone else who similarly nearly resorted to hari-kari in trying this.
import flash.events.MouseEvent;
import flash.events.Event;
var clipArray:Array = [btn_1,btn_2]; // Movieclip's called btn_1 etc...
var destArray:Array = ["page_1","page_2"]; Labels on timeline...
for (var i:int = 0; i < clipArray.length; i++) {
clipArray[i].buttonMode = true; // Define Button from Movie Clip
clipArray[i].useHandCursor = true; // Enable HandCursor over clip
clipArray[i].mouseChildren = false; // Define clip as single denomination
clipArray[i].addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
clipArray[i].addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
clipArray[i].addEventListener(Event.ENTER_FRAME, frameHandler);
clipArray[i].addEventListener(MouseEvent.CLICK,clickHandler, false, 0, true);
}
function clickHandler(event:MouseEvent):void {
for (var i:int = 0; i < clipArray.length; i++) {
if (event.currentTarget == clipArray[i]) {
this.gotoAndStop(destArray[i]);
clipArray[i].mouseEnabled = false;
clipArray[i].useHandCursor = false;
clipArray[i].alpha = 0.5;
} else {
clipArray[i].mouseEnabled = true;
clipArray[i].useHandCursor = true;
clipArray[i].alpha = 1;
}
}
}
function mouseOverHandler(e:MouseEvent){
e.target.onOff = true;
}
function mouseOutHandler(e:MouseEvent){
e.target.onOff = false;
}
function frameHandler(e:Event){
if(e.target.onOff){
e.target.nextFrame();
} else {
e.target.prevFrame();
}
}
This works fine, now however my understanding of whether it is 'good' code or not is an issue, if this could be improved in any way I'd like to know why and how as the problem with learning AS3 from 2 is that often you use code having seen it online without fully grasping the detail.
Tentatively, I'm pleased as this proved to be a nightmare to find or to resolve and hope it helps anyone else in a similar state of mind.
Adding MovieClip buttons with fluidity and which cancel out from an array became a three day mission when you're learning...
You might find you have more freedom if you put all of this in a class and use the Tween class to travel to your 'labels' instead of the timeline. It would mean that you would be able to remove your event listeners until your animation has finished.
Also it looks like you might be better off using the MouseEvent.ROLL_OVER and MouseEvent.ROLL_OUT
If I'm honest I don't know what some of your methods want to do without seeing your whole project, but I've quickly written a class for you. I've replaced animating between pages with just having your buttons animate to a ramdom location. (Remember to export your MovieClips you create with the IDE into actionscript, giving them the class name Button01, Button02 etc...). I hope this sends you in the right direction :)
package com
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
public class Main extends MovieClip
{
private var btn_1:Button01 = new Button01;
private var btn_2:Button02 = new Button02;
private var clipArray:Array = new Array();
private var xAxis:Number = 0;
private var yAxis:Number = 0;
private static const WIDTH:int = 300;
private static const HEIGHT:int = 250;
private var tweenButton:Tween;
public function Main()
{
makeArrays();
addChildren();
setEventListeners()
}
private function makeArrays():void
{
for(var i:uint=0; i<2; i++)
clipArray.push(this['btn_'+(i+1)]);
}
private function addChildren():void
{
for(var i:uint=0; i<clipArray.length; i++){
addChild(clipArray[i]);
clipArray[i].x = WIDTH*Math.random();
clipArray[i].y = HEIGHT*Math.random();
}
}
private function setEventListeners():void
{
for (var i:uint=0; i<clipArray.length; i++) {
clipArray[i].buttonMode = true; // Define Button from Movie Clip
//clipArray[i].useHandCursor = true; // Enable HandCursor over clip
//clipArray[i].mouseChildren = false; // Define clip as single denomination // DON'T NEED THIS WITH ROLL_OVER
clipArray[i].addEventListener(MouseEvent.ROLL_OVER, mouseOverHandler);
clipArray[i].addEventListener(MouseEvent.ROLL_OUT, mouseOutHandler);
clipArray[i].addEventListener(Event.ENTER_FRAME, frameHandler);
clipArray[i].addEventListener(MouseEvent.CLICK, clickHandler, false, 0, true);
}
}
private function tweenButtons(e:Event):void
{
var dispObj = e.currentTarget as DisplayObject;
dispObj.removeEventListener(MouseEvent.CLICK, clickHandler)
tweenButton = new Tween(dispObj, 'x', Regular.easeIn, dispObj.x, WIDTH*Math.random(), 1, true);
tweenButton = new Tween(dispObj, 'y', Regular.easeIn, dispObj.y, HEIGHT*Math.random(), 1, true);
tweenButton.addEventListener(TweenEvent.MOTION_FINISH, reattachEventListener);
}
private function reattachEventListener(e:Event):void
{
tweenButton.removeEventListener(TweenEvent.MOTION_FINISH, reattachEventListener);
for (var i:uint=0; i<clipArray.length; i++) {
if(!(hasEventListener(MouseEvent.CLICK)))
clipArray[i].addEventListener(MouseEvent.CLICK, clickHandler, false, 0, true);
}
}
private function clickHandler(e:MouseEvent):void
{
for (var i:uint=0; i<clipArray.length; i++) {
if (e.currentTarget == clipArray[i]) {
tweenButtons(e);
clipArray[i].buttonMode = false
clipArray[i].alpha = 0.5;
} else {
clipArray[i].buttonMode = true;
clipArray[i].alpha = 1;
}
}
}
private function mouseOverHandler(e:MouseEvent):void // I HAVE NO IDEA WHAT YOU'RE TRYING TO DO HERE
{
e.target.onOff = true;
}
private function mouseOutHandler(e:MouseEvent):void // I HAVE NO IDEA WHAT YOU'RE TRYING TO DO HERE
{
e.target.onOff = false;
}
private function frameHandler(e:Event):void // I HAVE NO IDEA WHAT YOU'RE TRYING TO DO HERE
{
if(e.target.onOff){
e.target.nextFrame();
}else{
e.target.prevFrame();
}
}
}
}