4

I'm working on an assignment of mine that a part of it requires me to put a red block in a grid layout in a JFrame. Afterwards the user should be able to change the position of that red block via arrow keys.

So far I've been able to add the red block into the grid layout. The problem is that I'm unable to move it.

Here is my Main.java. It calls for the JFrame in the Panel.java below:

import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;


public class Main {

public static void main( String[] args ) {

    Panel p = new Panel();

    p.setSize(870, 780);
    p.setVisible(true);
    p.setResizable(true);
    p.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}//END main

}//END Main

Panel.java. And here is the code having the KeyListener to move the red block. But it's not working.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class Panel extends JFrame implements Runnable{

static final int    GWIDTH = 200,
                    GHEIGHT = 200;

static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);


Icon bg = new ImageIcon( getClass().getResource("empty.jpg") );
Icon red = new ImageIcon( getClass().getResource("actor.jpg") );
Icon blue = new ImageIcon( getClass().getResource("blue.jpg") );

JLabel[] labels = new JLabel[48];

private int redPoint;

//Player navigation
private int i, j;



public Panel() {

    i = 1;
    j = 1;

    setPreferredSize(gameDim);
    setFocusable(true);
    requestFocus();
    setTitle("LabWork 10");
    setLayout(new GridLayout(6, 8, 10, 10));

    redPoint = (i*8)+j;


    for( int i=0 ; i<48 ; i++)
        labels[i] = new JLabel(bg);


    labels[redPoint] = new JLabel(red);


    for( int i=0 ; i<48 ; i++ )
        getContentPane().add(labels[i]);


    addKeyListener(new KeyListener() {

        @Override
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void keyPressed(KeyEvent e) {

            if( e.getKeyCode() == KeyEvent.VK_LEFT ) {
                j--;
                labels[redPoint] = new JLabel(bg);
                getContentPane().add(labels[redPoint]);
                redPoint = (i*8)+j;
                labels[redPoint] = new JLabel(red);
                getContentPane().add(labels[redPoint]);
            }

            if( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
                j++;
                labels[redPoint] = new JLabel(bg);
                getContentPane().add(labels[redPoint]);
                redPoint = (i*8)+j;
                labels[redPoint] = new JLabel(red);
                getContentPane().add(labels[redPoint]);
            }

            if( e.getKeyCode() == KeyEvent.VK_UP ){
                i--;
                labels[redPoint] = new JLabel(bg);
                getContentPane().add(labels[redPoint]);
                redPoint = (i*8)+j;
                labels[redPoint] = new JLabel(red);
                getContentPane().add(labels[redPoint]);
            }

            if( e.getKeyCode() == KeyEvent.VK_DOWN ){
                i++;
                labels[redPoint] = new JLabel(bg);
                getContentPane().add(labels[redPoint]);
                redPoint = (i*8)+j;
                labels[redPoint] = new JLabel(red);
                getContentPane().add(labels[redPoint]);
            }

        }//end keyPressed

    });//end addKeyListener

}//END panel







@Override
public void run() {



}

}

What is the reason for the code in the KeyListener being unable to reposition the red block?

Edit 1:

Here is the code with working moving tiles. Also with preventing going out of bounds.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class Panel extends JFrame implements Runnable{

static final int    GWIDTH = 200,
                    GHEIGHT = 200;

static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);


Icon bg = new ImageIcon( getClass().getResource("empty.jpg") );
Icon red = new ImageIcon( getClass().getResource("actor.jpg") );
Icon blue = new ImageIcon( getClass().getResource("blue.jpg") );

JLabel[] labels = new JLabel[48];

private int redPoint;

//Player navigation
private int i, j;



public Panel() {

    i = 1;
    j = 1;

    setSize(870, 780);
    setVisible(true);
    setResizable(true);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setPreferredSize(gameDim);
    setFocusable(true);
    requestFocus();
    setTitle("LabWork 10");
    setLayout(new GridLayout(6, 8, 10, 10));
    setFocusable(true);
    requestFocusInWindow();

    redPoint = (i*8)+j;


    for( int i=0 ; i<48 ; i++)
        labels[i] = new JLabel(bg);


    labels[redPoint] = new JLabel(red);


    for( int i=0 ; i<48 ; i++ )
        getContentPane().add(labels[i]);


    addKeyListener(new KeyListener() {

        @Override
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
         public void keyPressed(KeyEvent e) {

            if (e.getKeyCode() == KeyEvent.VK_LEFT)
               j--;

            if (e.getKeyCode() == KeyEvent.VK_RIGHT)
               j++;

            if (e.getKeyCode() == KeyEvent.VK_UP)
               i--;

            if (e.getKeyCode() == KeyEvent.VK_DOWN)
               i++;

            run();

          //for preventing going out of bounds 
            int oldRedPoint = redPoint;
            int old_i = i;
            int old_j = j;

            redPoint = (i * 8) + j;

            if( redPoint > 47 || redPoint < 0 ) {
                redPoint = oldRedPoint;
                i = old_i;
                j = old_j;
            }

            labels[oldRedPoint].setIcon(bg);
            labels[redPoint].setIcon(red);
         }

    });//end addKeyListener

}//END panel



@Override
public void run() {

    try {

    } catch (Exception e) {
        // TODO: handle exception
    }

}

}
The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156
Can
  • 4,516
  • 6
  • 28
  • 50
  • 1
    Seems like you doing all wrong, you initializing your `JLabel` again and again, so the previous one that is added to the `Content Pane` gets discarded, and God Knows what is happening,, too many initializations of `new JLabel()` every now and then, simply change the background of the said `JLabel` instead of adding a new `JLabel` to the already laid `Grid` – nIcE cOw Apr 22 '12 at 15:12
  • 1
    `Panel extends JFrame` Who needs an obfuscator, when you can write code like that? ;) – Andrew Thompson Apr 22 '12 at 15:14

1 Answers1

5

Your KeyListener problem is likely one of focus since KeyListeners only work for components that have the focus. One solution is to make your listened to component focusable via the setFocusable(...) method and then have it requestFocusInWindow() after it has been rendered.

Another more elegant solution is to use Key Bindings instead of a KeyListener, and bind to the appropriate InputMap, the one that is for JComponent.WHEN_IN_FOCUSED_WINDOW. Then you won't have to worry so much about focus issues.

There are lots of great examples on how to use Key Bindings on this site that you can search for, and some not so great ones as well that have been written by me.

Edit
It's not a focus issue, I stand corrected. To analyze further...

Edit 2
I think that your problem is that you're trying to add new JLabels to the contentPane when you shouldn't be doing that. Instead you should be swapping ImageIcons in the existing JLabels, since that is what you want to have happen -- the image to move, not the JLabel.

Edit 3
Yep that's it. You need to simplify things. For example:

     @Override
     public void keyPressed(KeyEvent e) {
        int oldRedPoint = redPoint;
        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
           j--;
        }

        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
           j++;
        }

        if (e.getKeyCode() == KeyEvent.VK_UP) {
           i--;
        }

        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
           i++;
        }
        redPoint = (i * 8) + j;
        labels[oldRedPoint].setIcon(bg);
        labels[redPoint].setIcon(red);
     }

Though I have to state that for the record I much prefer Key Bindings to key listeners.

Edit 4
Also, you'd better put in code to prevent your redPoint from going below 0 or above labels.length.

Also, if you were to ask a similar question, thanks for posting pertinent code, but please post code that is not dependent on outside resources such as images. I had to create my own images for your code to work:

private Icon createIcon(Color color) {
  BufferedImage img = new BufferedImage(IMG_W, IMG_H,
        BufferedImage.TYPE_INT_ARGB);
  Graphics g = img.getGraphics();
  g.setColor(color);
  g.fillRect(0, 0, IMG_W, IMG_H);
  g.dispose();
  return new ImageIcon(img);
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    @Can you can see if you get the key events correctly. Just put a simple System.out.println() at the beginning of each code you need to know if it gets executed or not. – Jakub Zaverka Apr 22 '12 at 15:10
  • Thanks, appreciate it. :) I tried that before and it works. The problem is probably about focusing. – Can Apr 22 '12 at 15:19
  • @Can: please see **Edit 2** for more on your issue. – Hovercraft Full Of Eels Apr 22 '12 at 15:30
  • @Can: please see **Edit 3** for the win. – Hovercraft Full Of Eels Apr 22 '12 at 15:33
  • Yeap. You're right. Thanks for your help. :D Nice coding by the way. – Can Apr 22 '12 at 15:38
  • I liked Edit 2 (+1 for that), will sort things up easily, though the logic as given by OP is too bad for the program, it is bound to give exceptions, once reached the end of the said `Row or Column` – nIcE cOw Apr 22 '12 at 15:42
  • @nIcE cOw Just realized that. Probably gonna have to make some changes. – Can Apr 22 '12 at 15:57
  • Agree with @nice cow, per Edit 4. – Hovercraft Full Of Eels Apr 22 '12 at 16:02
  • @CanSürmeli : Just try your hands on the code pasted, will delete it afterwards, let me know, when you done copying it. Though don't use KeyListeners use KeyBinding. HovercraftFullofEels, just gave you that valuable advice on this. – nIcE cOw Apr 22 '12 at 16:22
  • @HovercraftFullOfEels : Ahha, I missed that Edit 4, now caught that, that is great :-), LOL for image part, I had pasted my answer for OP's future references, adding images for SSCCE :-) – nIcE cOw Apr 22 '12 at 16:29