-2

What I'm trying to do is create in input box for a game I'm making that displays on-screen with a message such as

"Name: (input would appear here)"

What I did was pass in the message, which object I want my input to go to, and what function will use the variable(such as a function that sets the input to the player's name). Now, I could just access the input variable from the InputBox object, but, in the long run, this will be more efficient. I'm using Method.invoke to pass the function into the object I want with the input string as an argument. Here is my code:

public class InputBox extends Textbox {

    public String input = "";
    private String out;
    private Object obj;

    private int lastLastKey = 0;

    /** 
     * 
     * @param message
     * @param cl The object/class where the output variable is.
     * @param out The method to run. Only takes the input variable, so use this format: void toRun(String input)
     */
    public InputBox(String message, Object obj, String out) {
        super(message);
        this.out = out;
        this.obj = obj;
    }

    public void tick(Game game){                
        if (game.input.lastKey != 0 && !game.input.keys[KeyEvent.VK_ENTER]
                && !game.input.keys[KeyEvent.VK_SPACE] && !game.input.keys[KeyEvent.VK_SHIFT] && !game.input.keys[KeyEvent.VK_BACK_SLASH]){
            if(game.input.lastKey != lastLastKey) input+=Character.toUpperCase((char) game.input.lastKey);
        }else if(game.input.keys[KeyEvent.VK_ENTER] && !input.isEmpty() && !cleared){
            Method method = null;
            try {
                method = obj.getClass().getMethod(out, new Class[]{ String.class, Object.class });
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }

            try {
                method.invoke(obj, new Object[]{ input, obj });
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            cleared = true;
        }

        lastLastKey = game.input.lastKey;
    }

    public void render(Graphics g){
        if(!cleared){
            g.setColor(Color.white);
            g.fillRect(10, Display.height-110, Display.width-20, 100);

            g.setColor(Color.black);
            g.drawRect(10, Display.height-110, Display.width-20, 100);

            g.setFont(Game.smallFont);
            FontMetrics fm = g.getFontMetrics();
            g.drawString(message+" "+input, Display.width/2-fm.stringWidth(message+" "+input)/2, Display.height-50);
        }
    }

}
Zong
  • 6,160
  • 5
  • 32
  • 46
bloobchube
  • 39
  • 10
  • What is your question? – Sotirios Delimanolis Oct 03 '16 at 22:44
  • My question is that whenever I run this code, the variable is passed to the other class like I want, but the only thing I can do to it is use System.out.print on it. Other variables work, but this doesnt – bloobchube Oct 04 '16 at 00:08
  • I don't understand what that means. Can you please rephrase, ideally adding a [mcve] showing the issue with `System.out.print`? – Sotirios Delimanolis Oct 04 '16 at 00:20
  • When I pass the variable input to another class using Method.invoke, the variable is received correctly. I did a System.out.println(input) and it came up with RYAN, which was what I typed in. But when I try to display it on the actual screen, it doesn't come up, but if I use another variable, it does. I also tried writing it to a file; that didn't work either. – bloobchube Oct 04 '16 at 00:23

1 Answers1

0

Your description for the constructor says that the expected method has a signature of

void toRun(String input) {}

But your reflection code looks for a method with the signature

void toRun(String input, Object o) {}

If you are using Java 8 you can make use of a Consumer and remove all the reflection code:

public class InputBox extends Textbox {

    private Consumer<String> out;

    public InputBox(String message, Consumer<String> out) {
        this.out = out;
        ...
    }

    public void tick(Game game){
        ...
        out.apply(input);
        ...
    }
}

Assuming that your Player class has a method setName(String) like this:

public class Player {
    public void setName(String name) {
    }
}

you can create an InputBox with a method reference

public InputBox createNameInputBox(Player p) {
    return new InputBox("Name: ", p::setName);
}

or with a lambda expression

public InputBox createAlternateNameInputBox(Player p) {
    return new InputBox("Name: ", name -> p.setName(name));
}

To read more about lambda expressions and method references see the Java Tutorial series (https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html). For a discussion of whether you should use method references or lambda expressions see https://stackoverflow.com/a/24493905/5646962

Community
  • 1
  • 1
Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34