6 Replies Latest reply on Oct 8, 2009 8:16 AM by timo888

    What class should I extend for this custom control?

    timo888 Level 1

      The code below is my attempt at a mxml control to replace a custom context-menu  that my app needs on certain textInput controls.  Characters not on the keyboard are inserted into the text, replacing any selection, if applicable.  Flex AIR apps (which I need for local access to SQLite) don't let me do custom contextmenus when the control is not top-level.

       

      The custom component is encapsulated now in a Panel but I would like to have the composite control be nothing more than a textInput and a PopUpMenuButton right next to it.  Is that possible—not to have a container?  If so,  what class should I extend, if creating this as an ActionScript component?

       

      Thanks for the advice.

       

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="228" height="64"  creationComplete="onInit();" >
          <mx:TextInput id="mytextinput"   height="20"></mx:TextInput>   
         
          <mx:PopUpMenuButton id="mybutton" itemClick="onCharSelected(event);" x="159" y="-2" label="æ" width="41"  />
         
         
          <mx:Script>
           <![CDATA[
               import mx.utils.StringUtil;
               import mx.events.MenuEvent;
               import mx.events.ItemClickEvent;
              
               import mx.controls.TextArea;
              import mx.controls.Alert;
              import flash.events.*;
              import flash.display.Sprite;    
              import mx.collections.ArrayCollection;
                
                   
                  // use a point to track the selection-start and selection-end position for the text field
                  private var pt:Point=new Point;
             
                     
                  private var chars:ArrayCollection = new ArrayCollection(
                      [ {label:"ð", data : "ð"},
                        {label:"æ", data:"æ"},
                        {label:"þ", data:"þ"} ]);

       


                      // track the selection positions as the mouse is moved or text is entered
                  
                    private function onMouseEvent(e:MouseEvent): void{
                        pt.x=this.mytextinput.selectionBeginIndex;
                        pt.y=this.mytextinput.selectionEndIndex;
                    }
                   
                    private function trackSelectionIndices(e: Event):void {
                       pt.x=this.mytextinput.selectionBeginIndex;
                        pt.y=this.mytextinput.selectionEndIndex;  
                                              
                    }
                 
                 
                  private function onInit():void {
                      this.mytextinput.addEventListener(Event.CHANGE, trackSelectionIndices);
                      this.mytextinput.addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
                      this.mytextinput.addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);
                       
                      this.mybutton.dataProvider = chars;                     
                  }
                 
                  private function onCharSelected(e:MenuEvent):void {               
                                    
                      doInsert( e.item.data.toString(), this.mytextinput);
                  }
                 
              // insert the character chosen from the popup into the text field, replacing any selection, and then reset the insertion point
               private function doInsert(s:String, trgt:Object):void {
                                        
                  var v:String = TextInput(trgt).text;
                  var pre:String =v.substr(0,TextInput(trgt).selectionBeginIndex);
                  var post:String=v.substr(TextInput(trgt).selectionEndIndex, v.length-TextInput(trgt).selectionEndIndex);
                  var result:String = pre + s + post;
                  TextInput(trgt).text=result;
                  TextInput(trgt).setSelection(TextInput(trgt).selectionBeginIndex+s.length,TextInput(trgt) .selectionBeginIndex+s.length);
              }
                 
                ]]> 
               
          </mx:Script>        
         
      </mx:Panel>

        • 1. Re: What class should I extend for this custom control?
          leybniz Level 4

          you'd better go with Textinput as base class, and tweak it's updateDisplayList() method to position your incapsulated button right corner

          1 person found this helpful
          • 2. Re: What class should I extend for this custom control?
            timo888 Level 1

            Thank you for the suggestion. I am reading a PDF on updateDisplayList now to learn more about it.

             

            If the custom component extends TextInput, would the PopUpMenuButton be added as a child of the TextInput, i.e. this is the container?  I've tried doing that, and it almost works: mouse position tracking gets messed up, so the character-inserts don't always work, and the display properties are wacky.

             

            I would be content with an invisible container object to encapsulate both the TextInput and the Button.

            • 3. Re: What class should I extend for this custom control?
              leybniz Level 4

              Surely do, for the start you can use container say HBox will perfectly fits, to layout these two guys, but doing it based on TextInput solely might be quite tricky for you as a beginner.

              • 4. Re: What class should I extend for this custom control?
                timo888 Level 1

                Wiping perspiration from my brow as I abandon the difficult approach.

                 

                Here is the simpler approach where HBox encapsulates the TextInput and PopUpMenuButton. I am trying to figure out how to let the TextInput keep its selection highlight when it loses focus to the PopupMenuButton: setSelection does not cause the repaint.

                 

                package Search
                {
                    import flash.events.*;
                    import flash.geom.Point;
                   
                    import mx.collections.ArrayCollection;
                    import mx.containers.HBox;
                    import mx.controls.PopUpMenuButton;
                    import mx.controls.TextInput;
                    import mx.events.MenuEvent;
                   
                    public class UnicodeCharPopupMenu extends HBox
                    {
                        public function UnicodeCharPopupMenu()        {   
                                    super();   
                                    Init();
                                   
                        }
                   
                        private var mytextinput:TextInput = new TextInput;
                   
                        private var mybutton:PopUpMenuButton = new PopUpMenuButton;

                 

                        private function Init():void {
                            mytextinput.width=100;
                            mytextinput.height=22;
                            mybutton.width=44;           
                            this.width=200;
                            this.height=20;
                   
                           
                            visible=true;

                           mybutton.addEventListener(FocusEvent.FOCUS_IN, onMenuGotFocus;
                            mytextinput.addEventListener(Event.CHANGE, trackSelectionIndices);
                            mytextinput.addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
                            mytextinput.addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);
                            mybutton.addEventListener( MenuEvent.ITEM_CLICK, onCharSelected);
                            //mybutton.addEventListener(MenuEvent.MENU_HIDE, onMenuHide);
                            //mybutton.addEventListener(MenuEvent.MENU_SHOW, onMenuShow);

                            mybutton.dataProvider = chars;  
                            addChild(mytextinput);
                            addChild(mybutton);           
                           
                           
                        }

                 

                        // use a point to track the selection-start and selection-end position for the text field
                        private var pt:Point=new Point;
                       
                          private var chars:ArrayCollection = new ArrayCollection(
                                [ {label:"ð", data : "ð"},
                                  {label:"æ", data:"æ"},
                                  {label:"þ", data:"þ"} ]);

                 

                      //button got focus, repaint selection highlight
                        private function onMenuGotFocus(e:FocusEvent): void {           
                             mytextinput.setSelection(pt.x, pt.y);
                           
                           
                        }    
                       

                                   
                                 
                        /*    
                        // nothing selected, menu closed
                        private function onMenuHide(e:MenuEvent): void {
                            if (e.item.data==null) {
                                mytextinput.setFocus();
                            }
                        }    
                        */

                 

                        private function onCharSelected(e:MenuEvent):void {             
                                     
                                doInsert( e.item.data.toString(), mytextinput);
                        }
                           
                       public function getText():String {
                                return mytextinput.text;
                       }
                           
                            // track the selection positions as the mouse is moved or text is entered
                           
                             private function onMouseEvent(e:MouseEvent): void{
                                 pt.x=mytextinput.selectionBeginIndex;
                                 pt.y=mytextinput.selectionEndIndex;
                             }
                            
                             private function trackSelectionIndices(e: Event):void {
                                pt.x=mytextinput.selectionBeginIndex;
                                 pt.y=mytextinput.selectionEndIndex;  
                                                       
                             }
                            
                             private function doInsert(s:String, trgt:Object):void {
                                                  
                             var v:String = TextInput(trgt).text;
                             var pre:String =v.substr(0,pt.x);
                              var post:String=v.substr(pt.y, v.length-pt.y);
                            var result:String = pre + s + post;
                            TextInput(trgt).text=result;
                            TextInput(trgt).setFocus();
                            TextInput(trgt).setSelection(pt.x+s.length,pt.x+s.length);
                            pt.x = pt.x + s.length;
                            pt.y = pt.x;          
                             }
                       
                         
                    }
                }

                • 5. Re: What class should I extend for this custom control?
                  leybniz Level 4

                  The only thing I can suggest for you is to wrap your mytextinput with the class mysupertextinput and override updateDisplayList() there

                  always doing setSelection  I'm not to guaranty anything, but you should try this out before anything

                  1 person found this helpful
                  • 6. Re: What class should I extend for this custom control?
                    timo888 Level 1

                    Thanks I will try that approach. Before receiving your suggestion, I tried the following, but it doesn't do anything to keep the text-is-selected highlight on the TextInput:

                     

                    private function onTextInputLostFocus(e:FocusEvent): void {
                               if (e.relatedObject==mybutton) {
                                   e.preventDefault();
                                }           
                      }