4

How do I modify the Lable info's text by calling its settext method?

For e.g. depending in the button pressed I want to set the label's text appropriately

I get this error when I try accessing the label :

Cannot refer to a non-final variable i inside an inner class defined in a different method

        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

4 回答 4

3

有 4 种不同的方法可以解决此问题。我推荐选项 1。我将介绍所有选项,并在最后提供完整的解决方案。

  1. 将标签声明为最终标签。这是我在匿名课程上回答的一个问题。

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

    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 提出了另一种方法。创建一个临时的最终变量,将其分配给您当前的标签实例,并引用该临时变量。

我不推荐这个解决方案,我向你展示这个只是为了彻底。原因如下:

如果您稍后重新分配标签,则需要删除所有按钮的侦听器并每次创建新的侦听器。如果您打算重新分配您的标签,为什么不将标签声明为最终标签?它不是这里最好的方法。

    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.");    
     }
 });
于 2013-08-09T20:25:00.983 回答
2

William Morrison 列出了许多创建 ClickListener 的方法。我自己更喜欢匿名类的方法,我看到这是您问题中使用的方法。

您需要将匿名类之外的所有引用设为最终引用,以便您可以在内部引用它们。这就是 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() { }
}
于 2013-08-10T02:34:36.433 回答
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;
            };
      });
   }

}
于 2013-10-25T23:45:44.533 回答
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));
    }
}
于 2016-08-20T22:12:39.897 回答