如何访问libgdx中单击侦听器中的其他元素

时间:2013-08-09 20:16:31

标签: java android libgdx tablelayout

如何通过调用其settext方法来修改Lable信息的文本?

例如根据按下的按钮,我想适当地设置标签的文本

当我尝试访问标签时出现此错误:

不能在不同的内部类中引用非final变量i  方法

        Skin skin = new Skin(Gdx.files.internal("uiskin.json"));
        stage = new Stage();
        Gdx.input.setInputProcessor(stage);
        table = new Table();
        table.setFillParent(true);
        stage.addActor(table);

        String sentence = "One two three four five six seven eight";



        String[] temp = sentence.split(" ");
        ArrayList<String> words = new ArrayList<String>(Arrays.asList(temp));


        info = new Label( "Welcome to Android!", skin );

        for(int i=0; i<words.size();i++)
        {

            TextButton button = new TextButton( words.get(i), skin);
            table.add(button);

            button.addListener(new ClickListener() {
                @Override
                public void clicked(InputEvent event, float x, float y) {
                    Gdx.app.log("button","clicked");
                //info.setText(Integer.toString(i)); How to make this work?
//also how do I know which button is pressed?
                };
            });

        }


        table.row();
        table.add(info);


        Gdx.input.setInputProcessor(stage);

4 个答案:

答案 0 :(得分:3)

有4种不同的方法可以解决这个问题。我建议选项1.我将提供所有选项,并在最后提供完整的解决方案。

  1. 将标签声明为最终标签。 {匿名课程Here's a question I answered

    final Label info;
    //and then in your constructor initialize it...
    info = new Label("Welcome to Android",skin);
    
  2. 声明扩展ClickListener的内部类并引用外部类标签实例。这不要求info变量为final。

    public class MyLibgdxClass{
       class MyClickListener implements ClickListener{
            public void clicked(InputEvent event, float x, float y) {
                Gdx.app.log("button","clicked");
                info.setText(Integer.toString(i));
            };
        }
    }
    
  3. 在自己的文件中创建一个扩展ClickListener的类,并将其传递给您需要操作的标签。

    public class MyClickListener implements ClickListener{
        Label info;
        public MyClickListener(Label info){
            this.info = info;
        }
        public void clicked(InputEvent event, float x, float y) {
            Gdx.app.log("button","clicked");
            info.setText(Integer.toString(i));
        };
    }
    
  4. 评论中的Jyro117提出了另一种方法。创建临时最终变量,将其分配给当前标签实例,并引用临时变量。

  5. 我不推荐这个解决方案,我只是为了彻底而告诉你。原因如下:

    如果您稍后重新分配标签,则需要删除所有按钮的听众并每次都创建新的听众。如果您计划重新分配标签,为什么不宣布标签最终?这不是最好的方法。

        final Label tempLabel = info;
        button.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                Gdx.app.log("button","clicked");
                tempLabel.setText(i+"");
            }
        });
    

    对于检测单击哪个按钮,当您在循环中创建这些按钮时,在本地范围内,它们可以被声明为final而不会产生任何后果,因为您可能不会重新分配它们。这是我对完整解决方案的建议。

    //wherever you've declared label info, declare it as final.
    //note you'll need to initialize label in your constructor!
    final Label info;
    
    //...later on...
    for(int i=0; i<words.size();i++)
    {
        //declare button as final, so you can reference it in clicklistener
        final TextButton button = new TextButton( words.get(i), skin);
        //temporary final copy of i, so you can reference in clicklistener
        final int tempI = i;
        table.add(button);
        button.addListener(new ClickListener() {
             @Override
             public void clicked(InputEvent event, float x, float y) {
                 Gdx.app.log("button","clicked");
                 info.setText(tempI+""); //How to make this work?
                 //also how do I know which button is pressed?
                 Gdx.app.log("button",button.getText()+" was pressed.");    
         }
     });
    

答案 1 :(得分:2)

William Morrison列出了许多可以创建ClickListeners的方法。我更喜欢自己的匿名类方法,我发现这是你问题中使用的方法。

您需要在匿名类之外进行所有引用,以便您可以在其中引用它们。这就是java确保引用不会改变的方式。查看我的代码(和注释)以获得完整的解决方案,我只需要改变一些事情。 (我的皮肤文件也位于'skin / uiskin.json',所以如果你想使用这个代码,请记住这一点。)

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ClickTest implements ApplicationListener {
    private Stage stage;
    private Skin skin;

    @Override public void create() {
        Gdx.app.log("CREATE", "App Opening");

        this.skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
        stage = new Stage();
        Gdx.input.setInputProcessor(stage);
        Table table = new Table();
        table.setFillParent(true);
        stage.addActor(table);

        String sentence = "One two three four five six seven eight";
        String[] temp = sentence.split(" ");
        List<String> words = new ArrayList<String>(Arrays.asList(temp));

        final Label info = new Label("Welcome to Android!", skin);

        for (int i = 0; i < words.size(); i++) {
            // make i final here so you can reference it inside
            // the anonymous class
            final int index = i; 

            TextButton button = new TextButton(words.get(i), skin);
            table.add(button);

            button.addListener(new ClickListener() {
                @Override public void clicked(InputEvent event, float x, float y) {
                    // When you click the button it will print this value you assign.
                    // That way you will know 'which' button was clicked and can perform
                    // the correct action based on it.
                    Gdx.app.log("button", "clicked " + index);  

                    info.setText(Integer.toString(index));
                };
            });
        }

        table.row();
        // Changed this so it actually centers the label.
        table.add(info).colspan(words.size()).expandX(); 

        Gdx.input.setInputProcessor(stage);

        Gdx.gl20.glClearColor(0f, 0f, 0f, 1);
    }

    @Override public void render() {
        this.stage.act();
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        Gdx.gl20.glEnable(GL20.GL_BLEND);
        this.stage.draw();
    }

    @Override public void dispose() {
        Gdx.app.log("DISPOSE", "App Closing");
    }

    @Override public void resize(final int width, final int height) {
        Gdx.app.log("RESIZE", width + "x" + height);
        Gdx.gl20.glViewport(0, 0, width, height);
        this.stage.setViewport(width, height, false);
    }

    @Override public void pause() { }

    @Override public void resume() { }
}

答案 2 :(得分:0)

我更喜欢这个版本

public class MyClass{

   float test;    
   TextButton button;
   public void method(){
      button.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                 MyClass.this.test = 10.0f;
            };
      });
   }

}

答案 3 :(得分:0)

我为这种目标找到的最简单的策略是创建自己的自定义侦听器类。这样我就可以传递任何我需要传递给构造函数的东西 - 包括对我添加监听器的对象的引用。

for(int i = 0; i < buttonArray.length; ++i) {    
    buttonArray[i].addListener(new CustomListener(buttonArray[i]));
}

建立内部课程:

public class CustomListener extends ClickListener {

    Object listeningObject;

    public CustomListener(Object listeningObject) {
        this.listeningObject = listeningObject;
    }

    @Override
    public void clicked(InputEvent event, float x, float y) {
        ((Button)listeningObject).useAButtonMethod();
    }
}

您可以使用此常规策略通过构造函数将任何内容传递给自定义侦听器,最终与否。

PS:显然“useAButtonMethod()”不是一种方法,而是一种可以使用你想要的任何Button方法的指示。

编辑:在您的情况下,您可以执行以下操作:

for (int i = 0; i < words.size(); i++)
    // your stuff here.
    button.addListener(new CustomListener(info, i));
}

建立内部课程:

public class CustomListener extends ClickListener {

    Label label;
    int index;

    public CustomListener(Label label, int index) {
        this.label = label;
        this.index = index;
    }

    @Override
    public void clicked(InputEvent event, float x, float y) {
        Gdx.app.log("button", "clicked " + index);
        label.setText(Integer.toString(index));
    }
}