LibGDX ClickListeners touchDown method issues

I’m currently working on UI system for my game using Scene2d. I want buttons to respond right after I click them, so I override ClickListener touchDown method instead of using clicked method.

This button opens a table with more buttons, if the table is already open, it closes it:

// Save map button.
saveMap = new ImageButton(new ImageButtonStyle());
saveMap.getStyle().imageUp = uiSkin.getDrawable("save");
saveMap.getStyle().up = uiSkin.getDrawable("button_flat_up");
saveMap.getStyle().down = uiSkin.getDrawable("button_flat_down");

saveMap.addListener(new ClickListener() {
	
	public boolean touchDown(InputEvent event, float x,	float y, int pointer, int button) {
		
		if (button != Buttons.LEFT) {
			
			return false;
		}

		Game.resources.getSound("click_2").play();				
		if (saveBox.isVisible()) {
			
			saveBox.setVisible(false);	
			return false;
		}
		
		saveBox.setVisible(true);
		return true;
	}		
});

This is how the table looks like:

public class InputBox {

	public static float OFFSET = 20;

	private Table table;

	private TextField inputField;

	private TextButton okButton;
	private TextButton closeButton;

	private String saveText;

	public InputBox(Skin skin, float x, float y, float width, float height, boolean visible) {
	
		table = new Table();
		
		inputField = new TextField("", skin);

		okButton = new TextButton("Ok", skin);		
		okButton.addListener(new ClickListener() {
			
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				
				if (button != Buttons.LEFT) {
					
					return false;
				}
				Game.resources.getSound("click_2").play();
				table.setVisible(false);

				if (inputField.getText().equals("")) {

					saveText = null;
					return false;
				}

				saveText = inputField.getText();								
				return true;
			}
				
		});

		closeButton = new TextButton("Close", skin);
		closeButton.addListener(new ClickListener() {		
			
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {

				if (button != Buttons.LEFT) {
					
					return false;
				}
				
				closeButton.setChecked(false);
				Game.resources.getSound("click_2").play();

				saveText = null;				

				table.setVisible(false);				

				return true;
			}
		});

		table.setVisible(visible);

		table.setX(x);
		table.setY(y);

		table.setWidth(width);
		table.setHeight(height);

		table.add(inputField).colspan(2).center().width(width - OFFSET).expand().padRight(2);
		table.row();
		table.add(okButton).width(width / 2 - OFFSET / 2).right();
		table.add(closeButton).width(width / 2 - OFFSET / 2).left();
		table.pad(5);
	}
	
	...

	// This sets the visibility of the table
	public void setVisible(boolean visible) {
		
		table.setVisible(visible);
	}
	
	...
}

Now the issue that I’m having, is if I hide the table by clicking on one of its buttons and reopen it again, it displays itself with the last button being held down if I’m holding my left mouse button down on the reopen button (in this case the “saveMap” button).

I’ve recorded a video showing the issue: https://www.youtube.com/watch?v=Jf3WzU8G4dE

closeButton.setChecked(false);

What are the odds you have the down and up sprites around the wrong way?

You do not need to change buttons up and down states yourself, Scene2D does it for you. Remove that line and see how it goes. As you can see when you clicking down the close button does not actually change to the down state, because of that line.

The sprites are setup correctly I’m pretty sure, since I’m using the same skin over other buttons as well.

Removing that line didn’t fix the issue sadly, I forgot to remove it after I did some testing. Also I took another video showing some debug info, it seems that when I hide the table, the button state is set to pressed, because the isPressed() method keeps returning true: https://www.youtube.com/watch?v=xlqUd-9H3yc&feature=youtu.be

I printed out the info this way, just in case:

Game.resources.getGameFont().draw(sb, "Is button down:", 200, 420);

if (saveBox.getOkButton().isPressed()) {
	
	Game.resources.getGameFont().draw(sb, "Ok button: true", 200, 380);
	
} else {
	
	Game.resources.getGameFont().draw(sb, "Ok button: false", 200, 380);
}

if (saveBox.getCloseButton().isPressed()) {
	
	Game.resources.getGameFont().draw(sb, "Close button: true", 200, 400);
	
} else {
	
	Game.resources.getGameFont().draw(sb, "Close button: false", 200, 400);
}

Ah right I think I know the problem.

As soon as you set the tables visibility to false, I am sure all actors stop receiving updates.

Try setting a flag in the touch down method and instead of setting the table as not visible there do it on an update method that is called each frame.

Ideally your input box should extend table, this allows you to override the act method and do this that way.

Basically when you hide the table, or does not very updated next update.

The issue is still occurring with same symptoms, I’ve tried setting the visibility above and below the stage.act(dt) line.

The update method:


public void update(float dt) {

	stage.act(dt);

	float x = GameMath.screenMouse().x;
	float y = GameMath.screenMouse().y;

	// Set the save map string;		
	saveMapString = saveBox.getSaveTextOnce();

	// Check if the mouse is over any UI element.
	over = false;

	for (Actor actor : stage.getActors()) {

		if (isOver(actor, x, y)) {

		over = true;
		break;
		}
	}

	if (saveBox.isVisibleFlag()) {
		
		saveBox.setVisible(true);
		
	} else {
		
		saveBox.setVisible(false);
	}
}

The flag is being set this way outside of the table:


// Save map button.
saveMap.addListener(new ClickListener() {

	public boolean touchDown(InputEvent event, float x,	float y, int pointer, int button) {

	if (button != Buttons.LEFT) {

		return false;
	}

	Game.resources.getSound("click_2").play();				
	if (saveBox.isVisible()) {

		//saveBox.setVisible(false);	
		saveBox.setVisibleFlag(false);
		return false;
	}

	//saveBox.setVisible(true);
	saveBox.setVisibleFlag(true);
	return true;
	}		
});

Inside the table class:

closeButton.addListener(new ClickListener() {		

	@Override
	public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {

	if (button != Buttons.LEFT) {

		return false;
	}
	Game.resources.getSound("click_2").play();

	saveText = null;				

        // Setting the flag
	visibleFlag = false;

	return true;
	}
});

The isPressed() method is still returning true, so I guess to try to work with that would be useless if still using the setVisible method of the table.

Ok, I believe I figured this out. In my gameState I add a InputProcessor to the game. After fiddling around with it, I found out that it was causing this. To be more specific, this was causing the problem:


@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {

	releasedButton = -1;

	if (UI.isOver()) {

		return false;
	}
	if (button == Buttons.LEFT) {

		releasedButton = Buttons.LEFT;
	}
	if (button == Buttons.RIGHT) {

		releasedButton = Buttons.RIGHT;
	}		
	return true; // <--- Setting this to false fixes the issue.
}	

After fixing up the return values, everything seems to be working fine now, thank you for the replies!