Search code examples
javajframejpanelkeypresskeylistener

Separating KeyListener and JFrame into 2 different classes


I will show you two different codes to demonstrate what i'm asking for. The First code work fine it includes the JFrame and KeyListener in one class however what i want is to separate them.

First Code Below...

public class Fgui extends JFrame implements KeyListener{

private JPanel jp;
private Icon background = new ImageIcon(getClass().getResource("back2.png"));
private Icon monster = new ImageIcon(getClass().getResource("mol.png"));
protected JLabel mon;
private JLabel backG;
protected int monX = 300;
private int monY = 225;
protected int monDX = 0;
private int monDY = 0;
protected JLabel ct = new JLabel("Change Text");
protected int code;

public Fgui(){

    super("Crazy Monster Eating Game");
    this.setSize(750,400);
    this.setLayout(null);

    mon = new JLabel(monster);
    backG = new JLabel(background);

    this.addKeyListener(this);

    this.add(mon);
    mon.setSize(150,150);
    mon.setLocation(monX, 225);

    this.add(ct);
    ct.setSize(750,20);
    ct.setLocation(0,0);

    this.add(backG);
    backG.setSize(750,400);
    backG.setLocation(0,0);
}
public void keyPressed(KeyEvent e) {
    code = e.getKeyCode();
    if(code == KeyEvent.VK_LEFT){ 

        monDX = -40; 
        ct.setText("left key pressed");
        monX = monDX+monX;

        }
    else if(code == KeyEvent.VK_RIGHT){

        monDX = 40;
        ct.setText("right key pressed");
        monX = monDX+monX;

}else if(code == KeyEvent.VK_ESCAPE){

    try{ct.setText("ESC key pressed");
    this.dispose();}catch(Exception excep){System.out.println("Failed to EXIT!");}

}else{
    ct.setText("Key not registred");
    }
    mon.setLocation(monX, 225);
}
public void keyReleased(KeyEvent e) {} 
public void keyTyped(KeyEvent e) {}
}

Then i tried to separate them and ended up with the following code,

Second Code...

JFrame Half

public class Fgui extends JFrame {

private JPanel jp;
private Icon background = new ImageIcon(getClass().getResource("back2.png"));
private Icon monster = new ImageIcon(getClass().getResource("mol.png"));
protected JLabel mon;
private JLabel backG;
protected int monX = 300;
private int monY = 225;
protected int monDX = 0;
private int monDY = 0;
protected JLabel ct = new JLabel("Change Text");
protected int code;

public Fgui(){

    super("Crazy Monster Eating Game");
    this.setSize(750,400);
    this.setLayout(null);

    mon = new JLabel(monster);
    backG = new JLabel(background);

    KeyL KeyLObj = new KeyL();
    this.addKeyListener(KeyLObj);

    this.add(mon);
    mon.setSize(150,150);
    mon.setLocation(monX, 225);

    this.add(ct);
    ct.setSize(750,20);
    ct.setLocation(0,0);

    this.add(backG);
    backG.setSize(750,400);
    backG.setLocation(0,0);
}

}

KeyListener Half

public class KeyL extends Fgui implements KeyListener{

public void keyPressed(KeyEvent e) {
    code = e.getKeyCode();
    if(code == KeyEvent.VK_LEFT){ 

        monDX = -40; 
        ct.setText("left key pressed");
        monX = monDX+monX;

        }
    else if(code == KeyEvent.VK_RIGHT){

        monDX = 40;
        ct.setText("right key pressed");
        monX = monDX+monX;

}else if(code == KeyEvent.VK_ESCAPE){

    try{ct.setText("ESC key pressed");
    this.dispose();}catch(Exception excep){System.out.println("Failed to EXIT!");}

}else{
    ct.setText("Key not registred");
    }
    mon.setLocation(monX, 225);
}
public void keyReleased(KeyEvent e) {} 
public void keyTyped(KeyEvent e) {}
}

The Second Code here has two separate classes one is JFrame class the other is for KeyListener class but when i compile it, it does not work. I assume it is the problem with me adding the addKeyListener statement in a wrong way.

KeyL KeyLObj = new KeyL();
    this.addKeyListener(KeyLObj);

I tried adding it through the KeyL class but it didn't work either.

The reason i want to do this is because i don't want the code to be cramped all in one class, but separate it into 2 to make it seem more clean. And if i want to add more key events i can just do it in that one class.


Solution

  • The problem you're seeing is pretty simple. Because you make KeyL a subclass of Fgui, every time a new KeyL is constructed, all of the Fgui initialization code will get run.

    So you get to this line:

    KeyL KeyLObj = new KeyL();
    

    That creates a new KeyL, so before that line finishes, a new KeyL object has to be created. Since a KeyL is an Fgui, the Fgui constructor gets called. And the FGui constructor eventually gets to that same line, KeyL KeyLObj = new KeyL();, so the process repeats itself. You can never get past that line, because each new KeyL needs to make another KeyL before it can be fully constructed, so the program just keeps making new objects until it runs out of space.

    The answer is that there's no reason for KeyL to be a Fgui. Make it just implement KeyListener, and not extend Fgui. Then, make sure it has access to all the variables it needs to accomplish its task.

    Most of your variables should not be fields in the object; they should just be local variables. Anything that doesn't need to exist outside that function, or keep it's value between calls, should be changed to a local variable. It looks like the only two that matter are mon, ct, and the Fgui which you reference with this. So make those arguments into KeyL's constructor (as two JLabels and a JFrame), and then call your methods on those.