Editable MenuBar item

MMmmmm.. When you want to edit the label of any item in a "Tree" control in flex, you just have to set the tree editable, and click on the label to change the label name. But flex does not provide the feature/functionality to edit the menubar item because MenuBar extends "UIComponent" unlike other components like Tree thats extends List. List has item editor while MenuBar does not. What do you do in this case? Well, no option.. Make it and provide the functionality.

Look at below example. Click on "Menu1" in this example and it will change to editable text box with the label in it. Change the label to the name you want and press enter. The label of the "Menu1" will be changed. Perfect.



To provide this functionality for the menu bar item, you need to make few changes. Lets see step by step how to make these easy changes.

Step 1: As a first step, you need to create your custom menubar class that extends MenuBar class as you have to create your own item editor in the menubar.


public class EditableMenuBar extends MenuBar {
		
  public function EditableMenuBar() {
    super();
    this.addEventListener(MouseEvent.CLICK, menubarItemEditHandler);

  }

}


Step 2:When you click on the menubaritem, you want it to be editable and to make that happen, you should listen to Mouse "CLICK" event and in the event listener, create an item editor instance which is nothing but an instance of TextInput field and set the x, y co-ordinates, height and width of the TextInput field to menubar item you clicked. Then set the TextInput field's "text" with the menubar item label. Add this item editor instance to the MenuBar as child. Thats it. Now when you click on the menubar item, it changes to editable field with label in it. How? Well, actually what you are doing here is, you are creating a new TextInput control and moving to menubaritems's position, hence the menubar item is hidden by your new TextInput control (item editor) making it took like it has changed to editable field. This is how editable list is created (DataGrid, Tree, etc).


private var itemEditorInstance:IListItemRenderer;
private var customMenubarItem:CustomMenuBarItem;

public function EditableMenuBar() {
    super();
    this.addEventListener(MouseEvent.CLICK, menubarItemEditHandler);

}

private function menubarItemEditHandler(evt:Event):void{
  if (evt.target && evt.target.hasOwnProperty("data")) {
    var editedMenubarItem:MenuBarItem = MenuBarItem(evt.target);
    customMenubarItem = CustomMenuBarItem(evt.target.data);

    itemEditorInstance = (new ClassFactory(TextInput)).newInstance();
    itemEditorInstance.owner = this;
    itemEditorInstance.visible = true;
    itemEditorInstance.move(editedMenubarItem.x, editedMenubarItem.y);
    itemEditorInstance.setActualSize(editedMenubarItem.width, editedMenubarItem.height);
    var label:String = customMenubarItem.label;	        		
    itemEditorInstance.data = label;
    this.addChild(DisplayObject(itemEditorInstance));
    this.setChildIndex(DisplayObject(itemEditorInstance), this.numChildren - 1);

    //This is to set the focus to the item editor
    stage.focus = InteractiveObject(itemEditorInstance);
    TextInput(itemEditorInstance).setSelection(label.length, label.length);

  }

}

In the above "menubarItemEditHandler" function, first I am getting the selected (clicked) menubaritem as we need the x, y coordinates and height and width of the menubaritem. Then getting the data of the menubaritem as we need the label of the menubaritem. Later I am creating item editor instance (IListItemRenderer) and setting the properties of the same. Finally adding the item editor to menubar. Later just setting the focus to item editor. Not done yet........ Just one step left.

Step 3:Final step - everytime the key is up, you need to capture the input given by you and set it to menubaritem label. And then everytime you press enter key or tab key or click outside the menubaritem, you need to close the item editor and remove it from the MenuBar. To get these done, you just need to listen to "KeyboardEvent.KEY_UP", "KeyboardEvent.KEY_DOWN" and "FocusEvent.FOCUS_OUT" events. Check below code...


private var itemEditorInstance:IListItemRenderer;

public function EditableMenuBar() {
    super();
    this.addEventListener(MouseEvent.CLICK, menubarItemEditHandler);

}

private function menubarItemEditHandler(evt:Event):void{
  if (evt.target && evt.target.hasOwnProperty("data")) {
    ...

    itemEditorInstance.addEventListener(KeyboardEvent.KEY_UP, editKeyUpHandler);
	itemEditorInstance.addEventListener(KeyboardEvent.KEY_DOWN, editKeyDownHandler);
    itemEditorInstance.addEventListener(FocusEvent.FOCUS_OUT, editFocusOutHandler);
  }

}

private function editKeyUpHandler(event:KeyboardEvent):void {
  customMenubarItem.label = StringUtil.trim(event.target.text);
}

private function editKeyDownHandler(event:KeyboardEvent):void {
  if (event.keyCode == Keyboard.ENTER || event.keyCode == Keyboard.TAB) {	        		        		        	
    removeDisplayEditItem();
  }

}

public function editFocusOutHandler (event:FocusEvent):void	{
  removeDisplayEditItem();
}

//Remove Edit item added
public function removeDisplayEditItem():void	{
  
  if(this.itemEditorInstance != null){	
    this.itemEditorInstance.visible = false;
  
	if (this.contains(DisplayObject(itemEditorInstance))) {
      this.removeChildAt(this.numChildren - 1);
    }

    this.dataProvider.refresh();
    stage.focus = null;
  }

}
		

Done in 3 steps. Easy, isn't it?


You can download the example source code here.

Download the example code.





blog comments powered by Disqus