4 Replies Latest reply on Dec 28, 2007 2:12 PM by Garstyciuks

    Overdrawing button

    Garstyciuks
      I am creating a flex audio player and I have standard buttons such as Previous track, Next track, Play, Pause, Stop. I want to overdraw them with a specific shape, such as a triangle for play and a rectangle for stop. So I have created specific classes for each of the buttons and overrided the updateDisplayList function. Here is how I made my stop button:

      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
      {
      super.updateDisplayList(unscaledWidth, unscaledHeight);

      graphics.clear();

      graphics.beginFill(0x000000, 1.0);
      graphics.drawRect(dx, dx, 2*(cx-dx), 2*(cy-dx));
      graphics.endFill();
      }

      cx and cy are the center coordinates of the button and dx is the distance between the button side and the rectangle side.

      I have simillar code in other classes, but describing different shapes. It would work perfectly, but when the button is pushed down, the highlight completely overdraws my shape. Here is an image ilustrating the problem:

      Image

      The first button is in its normal state, the second one is when the mouse is over it and the last one is when it is pushed down.

      Thank you.

      edit: I'm using FLEX 3.
        • 1. Re: Overdrawing button
          Garyl Woolworth Level 1
          I think an easier way to go about this would be to just set the style of "icon" for the button based upon the action the button is taking "pause", "play". This would allow flex to take care of all of the display list changes for you and all you need to do is run one line of code of this.setStyle("icon", playIcon); if you are worried about the image sizes being more then what you want which they should only be 2k at most you could create the shapes within flash and embed the assets via the symbol names. This will retain the vector shapes and require the same amount of work to process visually as it does for you to draw them as you are. Honestly though using images for a square, and triangles shouldn't add anything to filesize compared to the classes you have to import just to draw the shapes the way you are now. I don't have flex on this computer but the basic logic is this.

          1) Embed individual assets and store them as a class so you can reference them.
          2) On your click handlers check to see if mode of the button which can be stored in a variable somewhere.
          private function clickHandler(event:MouseEvent):void {
          if(this.playMode == "play"){
          this.setStyle("icon", playIcon);
          } else if(this.playMode == "pause"){
          this.setStyle("icon", pauseIcon);
          }

          Once you change those styles it will trigger events built into the button to automatically update the display list to reflect the new icon. And since you embedded the images there wont be a load time. The icon style also applies to all states of the button whether it's down, up, over, off so you shouldn't have the issue you are having now.
          • 2. Re: Overdrawing button
            Garstyciuks Level 1
            Thanks for your reply.

            Is it possible to create an icon image on runtime, using vector graphics? I tried a lot of different stuff, but I still can't completely understand the way this stuff on FLEX is done. What I tried is to create the image in sprite class and then give it to the setStyle("icon", ...); function. However the application then complains that it can't convert my sprite into class "Class". I had no luck finding any information about this "Class".

            Thanks again.
            • 3. Re: Overdrawing button
              Garyl Woolworth Level 1
              To embed an image within a class and set a class to reference it you would use this syntax right above the constructor of your class but after the class definition itself.

              [Embed(source="playIcon.gif")]
              [Bindable] public var playIcon:Class;

              [Embed(source="pauseIcon.gif")]
              [Bindable] public var pauseIcon:Class;

              private var playMode:String = "paused";

              public function myClass(){ etc...

              Then your click handler would be able to reference those icons when you need to switch the icon.

              private function clickHandler(event:MouseEvent):void {
              if(this.playMode == "play"){
              this.setStyle("icon", playIcon);
              } else if(this.playMode == "pause"){
              this.setStyle("icon", pauseIcon);
              }
              • 4. Re: Overdrawing button
                Garstyciuks Level 1
                Thanks for you replies.

                OK, I will make it with embedded images. Thought I could pull this off only with vector graphics. Anyway, I was looking at the source code of the Button class and found this piece of code in updateDisplayList function:

                // The skins and icons get created on demand as the user interacts
                // with the Button, and as they are created they become the
                // frontmost child.
                // Here we ensure that the textField is the frontmost child,
                // with the current icon behind it and the current skin behind that.
                // Any other skins and icons are left behind these three,
                // with arbitrary layering.
                if (currentSkin)
                setChildIndex(DisplayObject(currentSkin), numChildren - 1);
                if (currentIcon)
                setChildIndex(DisplayObject(currentIcon), numChildren - 1);
                if (textField)
                setChildIndex(textField, numChildren - 1);

                So I managed to get my vector graphics shapes on top of everything using setChildIndex(...). I guess that my shape didn't get drawn before because Button class does this at some places:

                // Force a "render" event, which will cause updateDisplayList()
                // to show the appropriate skin for the new phase.
                event.updateAfterEvent();

                And I believe that it doesn't call the child class updateDisplayList(), so my shape doesn't get drawn on top of everything. Though I may be wrong.