haxeui / haxeui-flixel

The Flixel backend of the HaxeUI framework
MIT License
45 stars 13 forks source link

Removing NumberStepper in constructor causes an error #27

Closed AdamHarte closed 2 years ago

AdamHarte commented 2 years ago

Having a basic XML layout with a number-stepper, then trying to remove that component using removeComponent within the views constructor causes a Null access exception.

Expected Behavior

For any other component, they will just be removed, so I would expect the NumberStepper to do the same.

Current Behavior

Error callstack:

Called from haxe.ui.backend.ComponentImpl.~createTextInput.0 (haxe/ui/backend/ComponentImpl.hx line 941) Called from haxe.ui.backend.$TimerImpl.~constructor.0 (haxe/ui/backend/TimerImpl.hx line 17) Called from flixel.util.FlxTimer.onLoopFinished (flixel/util/FlxTimer.hx line 195) Called from flixel.util.FlxTimerManager.update (flixel/util/FlxTimer.hx line 285) Called from flixel.FlxGame.update (flixel/FlxGame.hx line 745) Called from flixel.FlxGame.step (flixel/FlxGame.hx line 677) Called from flixel.FlxGame.onEnterFrame (flixel/FlxGame.hx line 545) Called from openfl.text.TextField.~this_onMouseDown.0 (lime/app/Module.hx line 0) Called from openfl.events.EventDispatcher.dispatchEvent (openfl/events/EventDispatcher.hx line 402) Called from openfl.display.DisplayObject.dispatch (openfl/display/DisplayObject.hx line 1399) Called from openfl.display.Stage.broadcastEvent (openfl/display/Stage.hx line 1159) Called from openfl.display.Stage.broadcastEvent (openfl/display/Stage.hx line 1157) Null access .tf Uncaught exception: Null access .tf Called from haxe.$NativeStackTrace.callStack(C:\HaxeToolkit\haxe\std/hl/_std/haxe/NativeStackTrace.hx:25) Called from haxe.$NativeStackTrace.callStack(C:\HaxeToolkit\haxe\std/hl/_std/haxe/NativeStackTrace.hx:24) Called from haxe._CallStack.$CallStackImpl.callStack(C:\HaxeToolkit\haxe\std/haxe/CallStack.hx:52) Called from haxe._CallStack.$CallStackImpl.exceptionStack(C:\HaxeToolkit\haxe\std/haxe/CallStack.hx:65) Called from openfl.display.Stage.handleError(openfl/display/Stage.hx:1416) Called from openfl.display.Stage.broadcastEvent(openfl/display/Stage.hx:1163) Called from openfl.display.Stage.__onLimeRender(openfl/display/Stage.hx:1950) Called from lime.app._Event_lime_graphics_RenderContext_Void.dispatch(lime/_internal/macros/EventMacro.hx:91) Called from lime._internal.backend.native.NativeApplication.handleRenderEvent(lime/_internal/backend/native/NativeApplic ation.hx:371) Called from lime._internal.backend.native.NativeApplication.exec(lime/_internal/backend/native/NativeApplication.hx:146) Called from lime.app.Application.exec(lime/app/Application.hx:150) Called from $ApplicationMain.create(ApplicationMain.hx:130) Called from $ApplicationMain.main(ApplicationMain.hx:25) Called from .init(?:1)

Possible Solution

In haxeui-flixel/haxe/ui/backend/ComponentImpl.hx Line #941, there is a call to Toolkit.callLater. Inside the callback is _textInput.tf.visible = true;. It seems that the component is deleted by the time this delayed call is fired, so either _textInput or _textInput.tf is null. If I change the callback to check for null then it works correct i.e.

if(_textInput != null && _textInput.tf != null) {
     _textInput.tf.visible = true;
 }

But I wonder if there are other places where the same issue could happen. I also wonder if cancelling the callLater before it fires is a better solution?

Test app / minimal test case

PlayState.hx

package;

import flixel.FlxState;
import haxe.ui.containers.HBox;

class PlayState extends FlxState
{
    override public function create()
    {
        super.create();

        var view:PlayView = new PlayView();
        add(view);
    }
}

@:build(haxe.ui.ComponentBuilder.build("assets/ui/play-view.xml"))
class PlayView extends HBox
{
    public function new()
    {
        super();
        myStepper.parentComponent.removeComponent(myStepper);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<hbox width="100%" height="100%" style="spacing: 0;">
    <label text="Hello" />
    <number-stepper id="myStepper" pos="25" step="5" min="0" max="125" />
</hbox>

Context

Maybe there is more of an appropriate way to do what I am doing. But all I really want to do is hide some elements of my layout before anything is shown on screen, based on various parameters in code.

Your Environment

ianharrigan commented 2 years ago

hmmm, that is interesting, i would either expect all to crash, or none... i dont really understand what is different about the number stepper... ... ... unless... ... ... does it also happen with TextField (it may be that haxeui tries to destroy the internal, flixel based, text input field before its been created) - ill check it out.

Cheers, Ian

AdamHarte commented 2 years ago

I just tested all the basic components, and you are right. TextField does also have the issue. But that seems to be the only other component I have found. I have not tested any of the container components yet though.

ianharrigan commented 2 years ago

Cool - so yeah, my guess is there is a bug in haxeui-flixel where its trying to destroy the native (well, native to openfl) text input before its made, should be a simple fix.

ianharrigan commented 2 years ago

OK, this should be fixed now - if you are happy can you close this?

Cheers, Ian

AdamHarte commented 2 years ago

Perfect! TextField and NumberStepper both can be removed now without any issue. Thanks for the super quick fix!