[Solved] Change a Bitmap using MouseEvent triggers

There is probably a very simple fix for this particular issue that I am completely missing, and would like to know why my MouseEvent triggers are not changing the bitmap as expected in the below code:

    class TopBarButton extends Sprite
    {
    private var _base:Bitmap;
    private var _back:Bitmap;
    private var _backOver:Bitmap;
    private var _backDown:Bitmap;
    private var _text:TextField;
    
    public var Text(get, set):String;
    function get_Text() return _text.text;
    function set_Text(val) return _text.text = val;

    public function new() 
    {
        super();
        
        _back = new Bitmap(Assets.getBitmapData("img/TopBarButton.png"));
        _backOver = new Bitmap(Assets.getBitmapData("img/TopBarButtonOver.png"));
        _backDown = new Bitmap(Assets.getBitmapData("img/TopBarButtonDown.png"));
        _base = _back;
        
        _text = new TextField();
        _text.defaultTextFormat = Fonts.GetFormat('main-bold', 12, 0xFFFFFF);
        _text.autoSize = TextFieldAutoSize.LEFT;
        _text.selectable = false;
        _text.embedFonts = true;
        _text.wordWrap = false;
        _text.x = _text.width / 2;
        _text.y = 1;
        
        addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
        addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
        addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
        addEventListener(MouseEvent.MOUSE_UP, mouseUp);
        
        addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event):Void
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        
        addChild(_base);
        addChild(_text);
    }
    
    private function mouseOver(e:MouseEvent):Void
    {
        _base = _backOver;
    }
    
    private function mouseDown(e:MouseEvent):Void
    {
        _base = _backDown;
    }
    
    private function mouseOut(e:MouseEvent):Void
    {
        _base = _back;
    }
    
    private function mouseUp(e:MouseEvent):Void
    {
        _base = _backOver;
    }
    
    }

I have tried other ways around this, but can someone tell me what to do in this instance as it is rather annoying and rather embarrassing considering.

Option 1: update the _base.bitmapData field.

class TopBarButton extends Sprite
    {
    private var _base:Bitmap;
    private var _back:BitmapData;
    private var _backOver:BitmapData;
    private var _backDown:BitmapData;
    private var _text:TextField;
    
    public var Text(get, set):String;
    function get_Text() return _text.text;
    function set_Text(val) return _text.text = val;

    public function new() 
    {
        super();
        
        _back = Assets.getBitmapData("img/TopBarButton.png");
        _backOver = Assets.getBitmapData("img/TopBarButtonOver.png");
        _backDown = Assets.getBitmapData("img/TopBarButtonDown.png");
        _base = new Bitmap();
        
        _text = new TextField();
        _text.defaultTextFormat = Fonts.GetFormat('main-bold', 12, 0xFFFFFF);
        _text.autoSize = TextFieldAutoSize.LEFT;
        _text.selectable = false;
        _text.embedFonts = true;
        _text.wordWrap = false;
        _text.x = _text.width / 2;
        _text.y = 1;
        
        addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
        addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
        addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
        addEventListener(MouseEvent.MOUSE_UP, mouseUp);
        
        addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event):Void
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        
        addChild(_base);
        addChild(_text);
    }
    
    private function mouseOver(e:MouseEvent):Void
    {
        _base.bitmapData = _backOver;
    }
    
    private function mouseDown(e:MouseEvent):Void
    {
        _base.bitmapData = _backDown;
    }
    
    private function mouseOut(e:MouseEvent):Void
    {
        _base.bitmapData = _back;
    }
    
    private function mouseUp(e:MouseEvent):Void
    {
        _base.bitmapData = _backOver;
    }
    
}

Option 2: call removeChild() and addChild() every time.

private function mouseOver(e:MouseEvent):Void
{
    removeChild(_base);
    _base = _backOver;
    addChild(_base);
}

private function mouseDown(e:MouseEvent):Void
{
    removeChild(_base);
    _base.bitmapData = _backDown;
    addChild(_base);
}

private function mouseOut(e:MouseEvent):Void
{
    removeChild(_base);
    _base.bitmapData = _back;
    addChild(_base);
}

private function mouseUp(e:MouseEvent):Void
{
    removeChild(_base);
    _base.bitmapData = _backOver;
    addChild(_base);
}

I personally suggest option 1.

Thank you very much! I should give you a free cookie for all the help I receive from you :expressionless:

Went for option 1 in the end. I need to learn how to use this damn thing lol

As an example, imagine running these lines in immediate succession:

_base = _back;
addChild(_base);
_base = _backOver;

What you’ve done is added the _back bitmap as a child. You didn’t add a pointer named _base that you can update later, you added the current value of _base, which happens to be _back.

However, bitmaps have a quirk that allows you to pull it off. Because bitmap data can take up a lot of space, Flash keeps the data (BitmapData) separate from the display object (Bitmap). A Bitmap object will display whatever BitmapData object you give it, and multiple Bitmaps can refer to the same BitmapData.

(Don’t worry about restructuring your code to take advantage of this. Assets.getBitmapData() handles caching for you.)

Here’s the key. Because Bitmap and BitmapData are kept separate, you can change the data without changing the bitmap. If you had to change the Bitmap, you’d have to remove it as a child and then add the new one, but by setting the bitmapData property, you get to modify it in-place.

I hope that made sense. I know how confusing pointers/references can be.

If you are going to do something like this (and not use animation for the button states, etc) you might also consider using the openfl.display.SimpleButton class, which allows you to make the up, down, over and hit states into a single “simple” button