I'm using Netbeans (JDK 1.7) on Windows 8.1 to run an application that:
Graphics
object to draw a frog in the paintComponent()
of a 400x400 JPanel
;JFrame
for displaying purposes;This should be a very simple task, of course, but I'm having trouble understanding a specific behavior in this application.
Here is the problem: the very first time the window is displayed, the panel shows up at an offset (image below) when it shouldn't. I'm trying to understand why this is happening and how to solve it:
After one of the arrow keys are pressed on the keyboard the drawing gets displaced 5 pixels to the left/right/up/down. However, when this happens, the entire JPanel
seems to be moved to the (0,0) coordinate of the window (which is what I expected from the beginning), thus moving the drawing a lot more than it should:
I painted a black border on the edges of the panel to make the problem more apparent.
Here is the Short, Self Contained, Correct (Compilable), Example:
KAfrog.java:
import javax.swing.SwingUtilities;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class KAfrog
{
public static void main( String args[] )
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
} // end of anonymous innerclass
); // end of invokeLater
}
private static void createAndShowGUI()
{
System.out.println("Created GUI on EDT? " + SwingUtilities.isEventDispatchThread());
Window janela = new Window("Khan Academy Frog");
janela.addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
} // end of anonymous innerclass
); // end of addWindowListener
}
}
Window.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
class DrawingPanel extends JPanel
{
private int x = 50, y = 50;
public DrawingPanel() {
super();
setBorder(new LineBorder(Color.BLACK));
}
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void setX(int x) {
if (x < 0 || x >= 400)
return;
this.x = x;
repaint();
}
public void setY(int y) {
if (y < 0 || y >= 400)
return;
this.y = y;
repaint();
}
public int getX() { return this.x; }
public int getY() { return this.y; }
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("DrawingPanel::paintComponent: drawing at x:" + x + " y:" + y);
System.out.println("DrawingPanel::paintComponent: panel size " + getWidth() + "x" + getHeight());
// face
Color green = new Color(30, 204, 91);
g.setColor(green);
g.fillOval(x, y, 200, 100);
// mouth
g.setColor(Color.BLACK); // g.setColor(new Color(0, 0, 0));
g.fillOval(x+25, y+25, 150, 50);
// left eye
g.setColor(green);
g.fillOval(x+30, y-30, 45, 45); // background
g.setColor(Color.WHITE);
g.fillOval(x+35, y-25, 35, 35); // white eye sockets
g.setColor(Color.BLACK);
g.fillOval(x+48, y-15, 10, 10); // black eyes pretos
// right eye
g.setColor(green);
g.fillOval(x+110, y-30, 45, 45); // background
g.setColor(Color.WHITE);
g.fillOval(x+115, y-25, 35, 35); // white eye sockets
g.setColor(Color.BLACK);
g.fillOval(x+128, y-15, 10, 10); // black eyes
}
}
public class Window extends JFrame
{
DrawingPanel frog_panel;
public Window(String title)
{
super(title);
frog_panel = new DrawingPanel();
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
frog_panel.setX(frog_panel.getX()-5);
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
frog_panel.setX(frog_panel.getX()+5);
if (e.getKeyCode() == KeyEvent.VK_UP)
frog_panel.setY(frog_panel.getY()-5);
if (e.getKeyCode() == KeyEvent.VK_DOWN)
frog_panel.setY(frog_panel.getY()+5);
}
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }
}
);
add(frog_panel);
pack();
setVisible(true);
System.out.println("Window::Window: size is " + getWidth() + "x" + getHeight());
}
}
Does anyone know why this happens and how to fix it?
You overrode public int getX()
from javax.swing.JComponent.
It returns the current x coordinate of the component's origin. This method is preferable to writing component.getBounds().x, or component.getLocation().x because it doesn't cause any heap allocations.
Rename your methods public int getX()
and public int getY()
.
This should fix the problem.