question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Scene2d Listeners via Lambda

See original GitHub issue

Issue details

Currently LibGDX listeners in scene2d are always added via the addListener(...) method which takes a generic EventListener interface object. If you want to listen for a specific event you always have to implement an abstract listener class like ChangeListener, ClickListener, etc…

This creates a lot of boilerpalte code like

startGameButton.addListener( new ClickListener() {
    @Override
    public void clicked(InputEvent event, float x, float y) {
         // code comes here
    }
});

even for simple click listeners. It is not possible to use lambda methods/method references here which is really annoying (a bit like Java Swing was before Lambda methods were introduced in Java 8). If there were specific addClickListener( ButtonClickListener ) methods then the above code could be written in a single line (ignoring x, y) using lambda notation:

startGameButton.addClickListener( () -> ... );

This could easily be implemented on top of the current implementation via simple wrapper classes/methods like:

public interface ButtonClickListener { ... }

and in button classes:

public void addClickListener( final ButtonClickListener listener ) { 
    addListener( new ClickListener() {
        @Override
        public void clicked(InputEvent event, float x, float y) {
            listener.onClick();
        }
    };
)

`

Alternatively one could also migrate ClickListener to an interface with default methods. But since you try to keep Java 8 of LibGDX core the first way is probably better for now.

Please select the affected platforms

  • Android
  • iOS
  • HTML/GWT
  • Windows
  • Linux
  • MacOS

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:1
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
NathanSweetcommented, Apr 21, 2021

I use this in my app code:

static public void onChange (Actor actor, Runnable listener) {
	actor.addListener(new ChangeListener() {
		public void changed (ChangeEvent event, Actor actor) {
			listener.run();
		}
	});
}

static public void onClick (Actor actor, Runnable listener) {
	onClick(actor, Buttons.LEFT, listener);
}

static public void onClick (Actor actor, int button, Runnable listener) {
	actor.addListener(new ClickListener(button) {
		public void clicked (InputEvent event, float x, float y) {
			listener.run();
		}
	});
}

With a static import it allows eg:

onChange(someCheckbox, () -> {
	...
});

I don’t usually need the parameters, but it could be done with an interface other than Runnable.

It doesn’t feel great to have many addXxxListener methods solely for lambdas. Would addClickListener go on Actor? What about addChangeListener? I’m not sure Actor should really know about ChangeListener. Likely there are other listener types that definitely don’t belong on Actor, in which case we are sprinkling addXxxListener methods all over. It’s not the worst thing in the world, I’m just not sure we should go down that road. The static import solution above is almost as good, with the mess centralized (in app code, currently).

1reaction
mgsx-devcommented, Apr 21, 2021

looks familiar to me 😄 here’s my contribution, for what it worth :

public class UI {
	public static <T extends Actor> T change(T actor, Consumer<ChangeEvent> handler){
		actor.addListener(new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				handler.accept(event);
			}
		});
		return actor;
	}
	public static <T> void select(SelectBox<T> selectBox, Consumer<T> item) {
		change(selectBox, event->item.accept(selectBox.getSelected()));
	}
	public static <T extends Slider> T changeCompleted(T slider, Consumer<ChangeEvent> handler){
		slider.addListener(new ChangeListener() {
			@Override
			public void changed(ChangeEvent event, Actor actor) {
				if(!slider.isDragging()) handler.accept(event);
			}
		});
		return slider;
	}
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Lambda functions as targets - Elastic Load Balancing
You can register your Lambda functions as targets and configure a listener rule to forward requests to the target group for your Lambda...
Read more >
Libgdx Scene2d: Event Listener on Table - java - Stack Overflow
I wanted to know how you can detect a touch event on a table. Although I have tried using inputlistener.
Read more >
Scene2d - libGDX
scene2d is a 2D scene graph for building applications and UIs using a ... Each actor has a list of listeners that are...
Read more >
Event Handling - Lambda Expressions In Java 8: Tutorial 12
In this tutorial I go over how to use Lambda expressions to handle events in regards to creating new action listeners.
Read more >
AWS Lambda Events - Serverless Framework
If you are using AWS as your provider, all events in the service are anything in AWS that can trigger an AWS Lambda...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found