Pergunta

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
    }

}

}
Foi útil?

Solução

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);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top