Java- Key Bindings not working / actionPerformed not being called - java

I finally learned how to get graphics to work in java thanks to the guy who helped me on my previous question, but now I can't get key bindings to work. I know that the graphics method is called as I need it to, and I think that I have declared my key bindings properly, but the 'actionPerformed()' method won't call. I tried using the singleton pattern to get my player object across classes and I feel that it somehow screwed everything else up. I tried looking through quite a few other questions relating to my issue but I still couldn't figure it out, unless I'm overloooking something obvious. I'd REALLY appreciate if one of you majestic programming wizards could crack this one:
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;
public class Player {
private int xLoc, yLoc;
private boolean isFiring;
private String filename;
private ImageIcon imageicon;
private URL imgURL;
private static Player player;
public Player(int xl, int yl, boolean fire, String name){
xLoc = xl;
yLoc = yl;
isFiring = fire;
filename = name;
imgURL = getClass().getResource(name);
imageicon = new ImageIcon(imgURL);
}
public static Player getInstance(){
if(player == null){
player = new Player(0,0,false,"Dog.jpg");
}
return player;
}
public void fire(){
}
public int getX(){
return xLoc;
}
public int getY(){
return yLoc;
}
public void newX(int x){
xLoc = x;
}
public ImageIcon getImg() {
return imageicon;
}
public void newImg(ImageIcon ii){
imageicon = ii;
}
public URL getURL(){
return imgURL;
}
public void newURL(String n){
imgURL = getClass().getResource(n);
}
public void updateObject(){
imageicon = new ImageIcon(imgURL);
}
}
.
import java.awt.Graphics;
import java.net.URL;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class GamePanel extends JPanel{
int nameSwap = 0;
Player player;
public GamePanel(){
player = Player.getInstance();
repaint();
System.out.println("Repaint method called");
this.getInputMap().put(KeyStroke.getKeyStroke("A"), "moveLeft");
this.getActionMap().put("moveLeft", new MoveLR(-1));
this.getInputMap().put(KeyStroke.getKeyStroke("D"), "moveRight");
this.getActionMap().put("moveRight", new MoveLR(1));
this.getInputMap().put(KeyStroke.getKeyStroke("S"), "fire");
this.getActionMap().put("fire", new Fire());
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(player.getImg().getImage(), player.getX(), player.getY(), 50, 50, null);
//System.out.println("Graphics method called");
}
}
.
import java.awt.Color;
import javax.swing.JFrame;
public class Window {
public Window() {
JFrame frame = new JFrame("Epic Game");
frame.setSize(800,600);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GamePanel panel = new GamePanel();
frame.add(panel);
frame.setVisible(true);
while(true){
panel.repaint();
}
}
public static void main(String[] args){
Window window = new Window();
}
}
.
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Action;
public class MoveLR implements Action{
private int moveVal;
Player player;
public MoveLR(int mv){
moveVal = mv;
player = Player.getInstance();
System.out.println("New MoveLR object made");
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
player.newX(player.getX() + 1);
System.out.println("actionPerformed() called");
}
#Override
public void addPropertyChangeListener(PropertyChangeListener arg0) {
// TODO Auto-generated method stub
}
#Override
public Object getValue(String arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return false;
}
#Override
public void putValue(String arg0, Object arg1) {
// TODO Auto-generated method stub
}
#Override
public void removePropertyChangeListener(PropertyChangeListener arg0) {
// TODO Auto-generated method stub
}
#Override
public void setEnabled(boolean arg0) {
// TODO Auto-generated method stub
}
}

You're using the wrong InputMap. Use the getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). This way you'll bind to keys that are active when the JPanel doesn't have focus but is displayed in a window that does. The default InputMap is the one used for JComponent.WHEN_FOCUSED which is only valid when the bound component has focus, which is not what you want to do or use.
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"),
"moveLeft");
Also use classes that extend AbstractAction, not ones that implement Action as your Actions are not fully wired. And yes, you can repaint at the end of the actionPerformed as long as you have a reference to the JPanel, which the ActionEvent can get you.
Test program:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Window {
public Window() {
JFrame frame = new JFrame("Epic Game");
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GamePanel panel = new GamePanel();
frame.add(panel);
frame.setVisible(true);
// !! while (true) {
// panel.repaint();
// }
}
public static void main(String[] args) {
new Window();
}
}
#SuppressWarnings("serial")
class GamePanel extends JPanel {
int nameSwap = 0;
Player player;
public GamePanel() {
player = Player.getInstance();
repaint();
System.out.println("Repaint method called");
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "moveLeft");
this.getActionMap().put("moveLeft", new MoveLR(-1));
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "moveRight");
this.getActionMap().put("moveRight", new MoveLR(1));
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "fire");
this.getActionMap().put("fire", new Fire());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(player.getImg().getImage(), player.getX(), player.getY(), 50,
50, null);
// System.out.println("Graphics method called");
}
}
class Player {
private int xLoc, yLoc;
private boolean isFiring;
private String filename;
private ImageIcon imageicon;
// !! private URL imgURL;
private static Player player;
public Player(int xl, int yl, boolean fire, String name) {
BufferedImage img = new BufferedImage(20, 20, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.red);
g2.fillOval(2, 2, 16, 16);
g2.dispose();
imageicon = new ImageIcon(img);
xLoc = xl;
yLoc = yl;
isFiring = fire;
filename = name;
// !! imgURL = getClass().getResource(name);
// imageicon = new ImageIcon(imgURL);
}
public static Player getInstance() {
if (player == null) {
player = new Player(0, 0, false, "Dog.jpg");
}
return player;
}
public void fire() {
}
public int getX() {
return xLoc;
}
public int getY() {
return yLoc;
}
public void newX(int x) {
xLoc = x;
}
public ImageIcon getImg() {
return imageicon;
}
public void newImg(ImageIcon ii) {
imageicon = ii;
}
// !! public URL getURL(){
// return imgURL;
// }
// !! public void newURL(String n){
// imgURL = getClass().getResource(n);
// }
public void updateObject() {
// !! imageicon = new ImageIcon(imgURL);
System.out.println("update object called");
}
}
class MoveLR extends AbstractAction {
private int moveVal;
Player player;
public MoveLR(int mv) {
moveVal = mv;
player = Player.getInstance();
System.out.println("New MoveLR object made");
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
player.newX(player.getX() + moveVal);
((JPanel) e.getSource()).repaint();
System.out.println("actionPerformed() called");
}
}
class Fire extends AbstractAction {
public Fire() {
System.out.println("Fire created");
}
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Fire called");
}
}

Related

My keybinding didn't do its actionPerformed in JPanel

I've added keybinding on one of my JPanels. The problem is this keybinding didn't do its "actionPerformed". Even though I put a sysout in the actionPerformed, nothing was outputted on the console. Can someone help me with this problem? I've already tried to disable my buttons, but still my keybinding doesn't work.
package project.fin;
import java.awt.*;
import java.io.*;
import java.util.List;
import java.awt.event.*;
import javax.swing.*;
//Panel for my game
public class GamePlayPanel extends JPanel{
private Image current;
private Baby bayi;
public GamePlayPanel(String img) {
Dimension size = new Dimension(1200, 500);
this.setPreferredSize(size);
this.setMaximumSize(size);
this.setMinimumSize(size);
this.setSize(size);
this.setLayout(null);
//An baby object
bayi = new Baby(100, 410, 5);
//this is where my keyBinding initialized
bayi.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0), "moveRight");
bayi.getActionMap().put("moveRight", new Move_it(1));
}
//this is the action class that i want to put in my keybinding
private class Move_it extends AbstractAction{
int code;
public Move_it(int code) {
this.code=code;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("test\n");
if (this.code==1) {
bayi.MoveRight();
}
repaint();
}
}
//To draw my baby
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
bayi.draw(g);
}
}
This is my baby class:
package project.fin;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import java.awt.event.*;
public class Baby extends JComponent{
float x, y;
float speed;
Image current;
private List <Image> ImgPool;
private int Current;
public Baby(float x, float y, float speed) {
// TODO Auto-generated constructor stub
this.x = x;
this.y = y;
this.speed = speed;
ImgPool = new ArrayList<Image>();
//These are just some images that i use to build my moving baby
ImgPool.add(new ImageIcon("baby1_50.png").getImage());
ImgPool.add(new ImageIcon("baby2_50.png").getImage());
ImgPool.add(new ImageIcon("baby1_50.png").getImage());
ImgPool.add(new ImageIcon("baby3_50.png").getImage());
this.current = ImgPool.get(0);
this.Current = 0;
}
//The action that i want my baby to do when a key is pressed
public void MoveRight() {
if (x>600) return;
this.x+=speed;
if (this.Current==3)this.Current=0;
else
this.Current++;
this.current = this.ImgPool.get(Current);
}
public void draw(Graphics g) {
g.drawImage(this.current, (int)this.x, (int)this.y, null);
}
}
Baby isn't attached to the component hierarchy and therefore won't receive any key events. In fact, the design doesn't make sense. There's no need for Bady to extend from JPanel at all.
Instead, make use of the GamePlayPanel directly
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.*;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new GamePlayPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GamePlayPanel extends JPanel {
private Baby bayi;
public GamePlayPanel() {
//An baby object
bayi = new Baby(100, 410, 5);
//this is where my keyBinding initialized
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "moveRight");
getActionMap().put("moveRight", new Move_it(1));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1200, 500);
}
//this is the action class that i want to put in my keybinding
private class Move_it extends AbstractAction {
int code;
public Move_it(int code) {
this.code = code;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("test\n");
if (this.code == 1) {
bayi.moveRight();
}
repaint();
}
}
//To draw my baby
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
bayi.draw(g);
}
}
public class Baby {
float x, y;
float speed;
Image current;
private List<Image> ImgPool;
private int Current;
public Baby(float x, float y, float speed) {
// TODO Auto-generated constructor stub
this.x = x;
this.y = y;
this.speed = speed;
ImgPool = new ArrayList<Image>();
//These are just some images that i use to build my moving baby
ImgPool.add(new ImageIcon("baby1_50.png").getImage());
ImgPool.add(new ImageIcon("baby2_50.png").getImage());
ImgPool.add(new ImageIcon("baby1_50.png").getImage());
ImgPool.add(new ImageIcon("baby3_50.png").getImage());
this.current = ImgPool.get(0);
this.Current = 0;
}
//The action that i want my baby to do when a key is pressed
public void moveRight() {
if (x > 600) {
return;
}
this.x += speed;
if (this.Current == 3) {
this.Current = 0;
} else {
this.Current++;
}
this.current = this.ImgPool.get(Current);
}
public void draw(Graphics g) {
g.drawImage(this.current, (int) this.x, (int) this.y, null);
}
}
}

Why won't circle draw where I click

So I'm trying to draw a circle where a user clicks, which can then be re-sized by the bar down below. Everything works except for that the circle won't draw where I want it to. Any suggestions?
Here is my Panel
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.event.*;
public class TestClass extends JFrame {
private JSlider slide;
private MainClass myPanel;
public int x1=0;
public int y1=0;
public TestClass(){
super("The Title");
myPanel = new MainClass();
myPanel.setBackground(Color.YELLOW);
slide = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
slide.setMajorTickSpacing(10);
slide.setPaintTicks(true);
slide.addChangeListener(
new ChangeListener(){
public void stateChanged(ChangeEvent e){
myPanel.checkDiameter(slide.getValue());
}
}
);
HandlerClass handler = new HandlerClass();
slide.addMouseListener(handler);
add(slide, BorderLayout.SOUTH);
add(myPanel, BorderLayout.CENTER);
}
public int setX1(){
return x1;
}
public int setY1(){
return y1;
}
private class HandlerClass implements MouseListener{
#Override
public void mouseClicked(MouseEvent event) {
// TODO Auto-generated method stub
x1=event.getX();
y1=event.getY();
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
Here is the other important class which creates a window and call TestClass;
import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MainClass extends JPanel{
private int d = 10;
public void paintComponent(Graphics g){
super.paintComponent(g);
TestClass values = new TestClass();
g.setColor(Color.CYAN);
g.fillOval(values.setX1()+50, values.setY1(), d, d);
}
public void checkDiameter(int newD)
{
//New format for if statements
d = (newD >= 0 ? newD //if
: 10//else
);
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPreferredSize();
}
}
Hey Guys I found a way to get it working.
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.event.*;
public class TestClass extends JFrame {
private JSlider slide;
private MainClass myPanel;
public static int x1=0,y1=0;
public TestClass(){
super("The Title");
myPanel = new Panel();
myPanel.setBackground(Color.YELLOW);
//Allows you to re-size the drawn circle
slide = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
slide.setMajorTickSpacing(10);
slide.setPaintTicks(true);
slide.addChangeListener(
new ChangeListener(){
public void stateChanged(ChangeEvent e){
myPanel.checkDiameter(slide.getValue());
}
}
);
//Create a way to handle user mouse events
HandlerClass handler = new HandlerClass();
myPanel.addMouseListener(handler);
add(slide, BorderLayout.SOUTH);
add(myPanel, BorderLayout.CENTER);
}
private class HandlerClass implements MouseListener{
#Override
public void mouseClicked(MouseEvent event) {
// TODO Auto-generated method stub
Right here is what is new with the code, this method gets the x and y coordinates of a click and sends it to MainClass object myPanel which has the setPosition method; class show before.
myPanel.setPosition(event.getX(),event.getY());
repaint(); }
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
Here is the MainClass class, it is poorley named as it's not actually the main class...
import java.awt.;
import javax.swing.;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Panel extends JPanel{
private int x1,y1;
private int d = 10;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.CYAN);
g.fillOval(x1, y1, d, d);
}
public void checkDiameter(int newD)
{
//New format for if statements
d = (newD >= 0 ? newD //if
: 10//else
);
repaint();
}
public void setPosition(int newX, int newY) {
this.x1 = newX;
this.y1 = newY;
repaint();
}
public Dimension getPreferredSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPreferredSize();
}
}

Paint iconimage java swing?

I'm trying to create a program that draws up playing cards. The chart is drawn each time an object of class is created. As it stands now, I have five objects of the class, but only one card is being painted. I wonder of course why?
I also wonder how I could improve my movement of the cards.
Cards.java
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Cards extends JPanel implements MouseMotionListener, MouseListener{
Random rnd = new Random();
int X, posX;
int Y, posY;
int line;
int col;
String card;
boolean faceUp;
boolean pressOut;
static int numOfCards;
String [][] icons = {
{"img/c1.gif", "img/d1.gif", "img/h1.gif" , "img/s1.gif"},
{"img/c2.gif", "img/d2.gif", "img/h2.gif" , "img/s2.gif"},
{"img/c3.gif", "img/d3.gif", "img/h3.gif" , "img/s3.gif"},
{"img/c4.gif", "img/d4.gif", "img/h4.gif" , "img/s4.gif"},
{"img/c5.gif", "img/d5.gif", "img/h5.gif" , "img/s5.gif"},
{"img/c6.gif", "img/d6.gif", "img/h6.gif" , "img/s6.gif"},
{"img/c7.gif", "img/d7.gif", "img/h7.gif" , "img/s7.gif"},
{"img/c8.gif", "img/d8.gif", "img/h8.gif" , "img/s8.gif"},
{"img/c9.gif", "img/d9.gif", "img/h9.gif" , "img/s9.gif"},
{"img/c10.gif", "img/d10.gif", "img/h10.gif" , "img/s10.gif"},
{"img/cj.gif", "img/dj.gif", "img/hj.gif" , "img/sj.gif"},
{"img/cq.gif", "img/dq.gif", "img/hq.gif" , "img/sq.gif"},
{"img/ck.gif", "img/dk.gif", "img/hk.gif" , "img/sk.gif"}
};
public Cards() {
numOfCards++;
addMouseListener(this);
addMouseMotionListener(this);
this.X = rnd.nextInt(300);
this.Y = rnd.nextInt(300);
this.line = rnd.nextInt(13);
this.col = rnd.nextInt(4);
this.card = icons[line][col];
this.faceUp = rnd.nextBoolean();
this.pressOut = false;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(faceUp == true){
ImageIcon icon = new ImageIcon(this.getClass().getResource(card));
g.drawImage(icon.getImage(), this.X, this.Y, this);
} else {
ImageIcon icon = new ImageIcon(this.getClass().getResource("/img/b1fv.gif"));
g.drawImage(icon.getImage(), this.X, this.Y, this);
}
}
#Override
public void mouseClicked(MouseEvent e) {
if(this.faceUp == false){
this.faceUp = true;
this.repaint();
} else {
this.faceUp = false;
this.repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
this.posX = this.getX() - e.getX();
this.posY = this.getY() - e.getY();
if (this.card != null) {
updateLocation(e);
}else{
pressOut = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
updateLocation(e);
}
#Override
public void mouseDragged(MouseEvent e) {
if (!pressOut) {
updateLocation(e);
}
}
public void updateLocation(MouseEvent e){
this.setLocation(this.posX + e.getX(), this.posY + e.getY());
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Table.java
import java.awt.Color;
import java.awt.Frame;
import javax.swing.JFrame;
public class Table{
public static void main(String[] args) {
JFrame frame = new JFrame("Cards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addMouseListener(null);
frame.addMouseMotionListener(null);
frame.setBackground(Color.GREEN);
frame.setSize(400,600);
Cards c1 = new Cards();
Cards c2 = new Cards();
Cards c3 = new Cards();
Cards c4 = new Cards();
Cards c5 = new Cards();
System.out.println(c1.card);
System.out.println(c2.card);
System.out.println(c3.card);
System.out.println(c4.card);
System.out.println(c5.card);
System.out.println(c5.numOfCards);
frame.add(c1);
frame.add(c2);
frame.add(c3);
frame.add(c4);
frame.add(c5);
frame.setVisible(true);
}
}
The default layout for a JFrame is BorderLayout.
Try using GridLayout, for example
frame.setLayout(new GridLayout(0, 3));
Don't load the image in the paintComponent method, this method should exit as fast as possible, instead, pre-load the images...
public class Cards extends JPanel implements MouseMotionListener, MouseListener{
//...
private Image face;
private Image back;
//...
public Cards() {
//...
face = new ImageIcon(this.getClass().getResource(card)).getImage();
back = ImageIcon icon = new ImageIcon(this.getClass().getResource("/img/b1fv.gif")).getImage();
//...
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(faceUp){
g.drawImage(face, this.X, this.Y, this);
} else {
g.drawImage(back , this.X, this.Y, this);
}
}
You should also be overriding the getPreferredSize method of the JPanel, this works with the layout manager API to allow it to make decisions about how best to layout component...
public Dimension getPreferredSize() {
return face == null ? super.getPreferredSize() : new Dimension(face.getWidth(this), face.getHeight(this));
}
This will now allow you to use JFrame#pack instead of JFrame#setSize

Cannot manage to use ActionListener between two classes

I try to implement two classes, one dedicated to the interface and the other one dedicated to the canvas allowing user to draw shapes on it.
So basically, let's take one of my button, here is my Jbutton bCircle where I want to initialize the action in an anonymous class. I have put just the specific piece :
public class Application extends JFrame implements ActionListener {
toolBar.add(Box.createHorizontalGlue());
toolBar.add(Box.createVerticalGlue());
toolBar.add(bSquare, toolBar.getComponentCount() - 1);
toolBar.add(bCircle, toolBar.getComponentCount() - 1);
bCircle.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
//Action ?????
}
});
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
toolBar.add(bTriangle, toolBar.getComponentCount() - 1);
toolBar.add(bErase, toolBar.getComponentCount() - 1);
toolBar.setOrientation(SwingConstants.VERTICAL);
container.add(toolBar, BorderLayout.WEST);
}
And in the other class, here is the action I want the selected state of the Jbutton bCircle to execute when I click on the canvas :
public class DrawingCanvas extends JPanel implements MouseListener, MouseMotionListener {
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == bCircle) {
shapes.add(new Circle(e.getX(),e.getY()));
}
repaint();
}
}
shapes is a ArrayList stocking the shapes to make the canvas easier to clean, Circle is a class which only contains drawing of the circle.
At the end, the purpose is to allow user to click first on four buttons representing four shapes, then draw them by a mouse pressed on the canvas. But I don't know how to link theses two classes, please help me,
Thanks in advance,
P.S : the full Application class (interface) that I have updated a second time:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
public class Application extends JFrame implements ActionListener {
{
//Set appearance Look & Feel for the window
try { javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch(Exception e) {
e.printStackTrace();
}
}
private DrawingCanvas canvas = new DrawingCanvas();
private JPanel container = new JPanel();
private JPanel commandes = new JPanel();
private JMenuBar menu = new JMenuBar();
private JMenu newFile = new JMenu();
private JMenu open = new JMenu();
private JMenu save = new JMenu();
private JFileChooser fileChooser;
private JToolBar toolBar = new JToolBar();
private JButton bSquare = new JButton("Square");
private JButton bRectangle = new JButton("Rectangle");
private JButton bCircle = new JButton("Circle");
private JButton bTriangle = new JButton("Triangle");
private JButton bErase = new JButton("CLEAR");
//public static boolean bIsSelected = false;
public Application(){
this.setTitle("Animation");
this.setSize(579, 432);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
container.add(canvas, BorderLayout.CENTER);
this.setContentPane(container);
toolBar.add(Box.createHorizontalGlue());
toolBar.add(Box.createVerticalGlue());
toolBar.add(bSquare, toolBar.getComponentCount() - 1);
toolBar.add(bCircle, toolBar.getComponentCount() - 1);
bCircle.addActionListener(new SampleActionListener(canvas, new Circle()));
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
toolBar.add(bTriangle, toolBar.getComponentCount() - 1);
toolBar.add(bErase, toolBar.getComponentCount() - 1);
bErase.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent erase){
canvas.getShapes().clear();
repaint();
}
});
toolBar.setOrientation(SwingConstants.VERTICAL);
container.add(toolBar, BorderLayout.WEST);
menu.add(newFile);
newFile.setIcon(new ImageIcon("src/images/new.png"));
menu.add(open);
open.setIcon(new ImageIcon("src/images/open.png"));
menu.add(save);
save.setIcon(new ImageIcon("src/images/save.png"));
this.setJMenuBar(menu);
}
public class SampleActionListener implements ActionListener {
private final DrawingCanvas canvas2;
private final ShapeGenerator shapeGenerator;
public SampleActionListener(DrawingCanvas canvas, ShapeGenerator shapeGenerator) {
this.canvas2 = canvas;
this.shapeGenerator = shapeGenerator;
}
public void actionPerformed(ActionEvent event) {
this.canvas2.setShapeGenerator(shapeGenerator);
}
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Application App = new Application();
}
}
Here is the class for the canvas, uploaded a second time as well :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.JPanel;
public class DrawingCanvas extends JPanel implements MouseListener {
private ArrayList<Shape> shapes = new ArrayList<>();
private Shape shapeUnderMouse = null;
public ArrayList<Shape> getShapes() {
return shapes;
}
public void setShapes(ArrayList<Shape> shapes) {
this.shapes = shapes;
}
public DrawingCanvas() {
super();
addMouseListener(this);
}
public void paint(Graphics g){
for(int i = 0;i < shapes.size();i++){
shapes.get(i).paint(g);
}
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void addShape(Shape anyShape)
{
shapes.add(anyShape);
}
#Override
public void mousePressed(MouseEvent e) {
shapes.add(this.shapeGenerator.getGeneratedShape(e.getX(), e.getY()));
repaint();
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void setShapeGenerator(ShapeGenerator shapeGenerator) {
// TODO Auto-generated method stub
}
Now, the class shape :
import javax.swing.JPanel;
public class Shape extends JPanel{
protected int posX;
protected int posY;
/*public Shape(int posX, int posY) {
super();
this.posX = posX;
this.posY = posY;
}*/
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
}
My little circle class :
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Float;
import javax.swing.JPanel;
public class Circle extends Shape implements ShapeGenerator{
/*public Circle(int posX, int posY) {
super(posX, posY);
// TODO Auto-generated constructor stub
}*/
public void paint(Graphics g){
g.fillOval(posX,posY,40,40);
g.setColor(Color.blue);
}
public Shape getGeneratedShape(int x, int y) {
return new Ellipse2D.Float(x, y, 10, 10); //--> does not work, ask me to change method type to a float
return new Circle();
}
}
And finally the interface, all the class are in separate classes :
public interface ShapeGenerator {
Shape getGeneratedShape(int posX, int posY);
}
In fact, it's pretty easy. Don't use anonymous class.
For example, with your code, you just have to attach a defined listener. For example :
bCircle.addActionListener(new SampleActionListener(pan, new CircleShapeGenerator()));
Here is the SampleActionListener witch implements the ActionListener interface
public class SampleActionListener implements ActionListener {
private final DrawingCanvas canvas;
private final ShapeGenerator shapeGenerator;
public SampleActionListener(DrawingCanvas canvas, ShapeGenerator shapeGenerator) {
this.canvas = canvas;
this.shapeGenerator = shapeGenerator;
}
public void actionPerformed(ActionEvent event) {
this.canvas.setShapeGenerator(shapeGenerator);
}
}
Here is the class CircleShapeGenerator
public class CircleShapeGenerator implements ShapeGenerator {
public Shape getGeneratedShape(int x, int y) {
return new Ellipse2D.Float(x, y, 10, 10);
}
}
and the interface ShapeGenerator
public interface ShapeGenerator {
Shape getGeneratedShape(int x, int y);
}
and, if you want to add the action listener on the rectangle button, it's really easy now. create this class:
public class RectangleShapeGenerator implements ShapeGenerator {
public Shape getGeneratedShape(int x, int y) {
return new Rectangle2D.Float(x, y, 10, 10);
}
}
and in your application class, add the following code
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
bRectangle.addActionListerner(pan, new RectangleShapeGenerator() )
for your method paint in your DrawingCanvas, i think, you should use a code like this :
for (Shape s : shapes) {
Graphics2D g2 = (Graphics2D) g;
g2.draw(s);
}
BR,
Patouche
Sorry for my english, i know it's not really perfect...
First of all, remove your class Shape. You don't need to. Shape is a interface defined by Java. Use this interface instead.
Your setter for ShapeGenerator in the DrawingCanvas class do nothing. So add it. Your method paint is not correct.
public class DrawingCanvas extends JPanel implements MouseListener {
// Shape here is the java.awt.Shape from java.
private ArrayList<Shape> shapes = new ArrayList<>();
private ShapeGenerator shapeGenerator;
...
...
public void paint(Graphics g){
super.paint(g);
for (Shape s : shapes) {
Graphics2D g2 = (Graphics2D) g;
g2.draw(s);
}
}
...
#Override
public void mousePressed(MouseEvent e) {
shapes.add(this.shapeGenerator.getGeneratedShape(e.getX(), e.getY()));
repaint();
}
public void setShapeGenerator(ShapeGenerator shapeGenerator) {
this.shapeGenerator = shapeGenerator;
}
}
You class Circle is really to complex. It's simple and this method don't need any paint method. You class Circle is really simple :
public class Circle implements ShapeGenerator{
public Shape getGeneratedShape(int x, int y) {
// This will return a java.awt.Shape instance
return new Ellipse2D.Float(x, y, 10, 10);
}
}
And i thinks, that's all.
Here is the solution to your problem. But it's really dirty... Like i said, there is no sense to have a Shape that is inhereted from JPanel !!
public class Application extends JFrame implements ActionListener {
{
// Set appearance Look & Feel for the window
try {
javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
}
private final DrawingCanvas pan = new DrawingCanvas();
// don't use to many field, it's confusing and not necessary.
// you can do local var instead.
private final JPanel container = new JPanel();
private final JPanel commandes = new JPanel();
private final JMenuBar menu = new JMenuBar();
private final JMenu newFile = new JMenu();
private final JMenu open = new JMenu();
private final JMenu save = new JMenu();
private JFileChooser fileChooser;
private final JToolBar toolBar = new JToolBar();
private final JButton bSquare = new JButton("Square");
private final JButton bRectangle = new JButton("Rectangle");
private final JButton bCircle = new JButton("Circle");
private final JButton bTriangle = new JButton("Triangle");
private final JButton bErase = new JButton("CLEAR");
public Application() {
this.setTitle("Animation");
this.setSize(579, 432);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
container.add(pan, BorderLayout.CENTER);
this.setContentPane(container);
toolBar.add(Box.createHorizontalGlue());
toolBar.add(Box.createVerticalGlue());
toolBar.add(bSquare, toolBar.getComponentCount() - 1);
toolBar.add(bCircle, toolBar.getComponentCount() - 1);
bCircle.addActionListener(new SampleActionListener(pan, new CircleShapeGenerator()));
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
// bRectangle.addActionListener(new SampleActionListener(pan, new
// RectangleShapeGenerator()));
toolBar.add(bTriangle, toolBar.getComponentCount() - 1);
toolBar.add(bErase, toolBar.getComponentCount() - 1);
toolBar.setOrientation(SwingConstants.VERTICAL);
container.add(toolBar, BorderLayout.WEST);
menu.add(newFile);
newFile.setIcon(new ImageIcon("src/images/new.png"));
menu.add(open);
open.setIcon(new ImageIcon("src/images/open.png"));
menu.add(save);
save.setIcon(new ImageIcon("src/images/save.png"));
this.setJMenuBar(menu);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Application App = new Application();
}
}
We keep the CircleShapeGenerator class
public class CircleShapeGenerator implements ShapeGenerator {
#Override
public CircleShape getGeneratedShape(int x, int y) {
CircleShape c = new CircleShape();
c.setCanvasX(x);
c.setCanvasY(y);
return c;
}
}
The circle shape
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class CircleShape extends Shape {
private final Ellipse2D.Float ellipse2D;
public CircleShape() {
this.ellipse2D = new Ellipse2D.Float();
this.setRadius(20);
}
private void setRadius(int r) {
this.ellipse2D.height = r;
this.ellipse2D.width = r;
}
#Override
public void setCanvasX(int canvasX) {
this.canvasX = canvasX;
this.ellipse2D.x = canvasX;
}
#Override
public void setCanvasY(int canvasY) {
this.canvasY = canvasY;
this.ellipse2D.y = canvasY;
}
#Override
public java.awt.Shape getTrueShape() {
return this.ellipse2D;
}
}
A class for the contextual menu to edit your shape
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
class ContextualShapeMenu extends JPopupMenu {
private final Shape shape;
public ContextualShapeMenu(Shape shape) {
this.shape = shape;
JMenuItem anItem = new JMenuItem("Edit the size");
add(anItem);
}
}
The DrawingCanvas class
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.google.common.collect.Lists;
public class DrawingCanvas extends JPanel implements MouseListener {
protected ArrayList<Shape> shapes = new ArrayList<Shape>();
private ShapeGenerator shapeGenerator;
public ArrayList<Shape> getShapes() {
return shapes;
}
public void setShapes(ArrayList<Shape> shapes) {
this.shapes = shapes;
}
public DrawingCanvas() {
super();
addMouseListener(this);
}
#Override
public void paint(Graphics g) {
super.paint(g);
for (Shape s : shapes) {
s.paint(g);
}
}
#Override
public void mouseClicked(MouseEvent e) {
switch (e.getButton()) {
case MouseEvent.BUTTON1:
shapes.add(this.shapeGenerator.getGeneratedShape(e.getX(), e.getY()));
break;
default:
Shape shape = getShapeUnderMouse(e);
if (shape != null) {
ContextualShapeMenu menu = new ContextualShapeMenu(shape);
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
repaint();
}
private Shape getShapeUnderMouse(MouseEvent e) {
List<Shape> reversed = Lists.reverse(this.shapes);
for (Shape s : reversed) {
if (s.contains(e.getX(), e.getY())) {
return s;
}
}
return null;
}
#Override
public void mouseEntered(MouseEvent e) {
// Do nothing
}
#Override
public void mouseExited(MouseEvent e) {
// Do nothing
}
#Override
public void mousePressed(MouseEvent e) {
// Do nothing
}
#Override
public void mouseReleased(MouseEvent e) {
// Do nothing
}
public void setShapeGenerator(ShapeGenerator shapeGenerator) {
this.shapeGenerator = shapeGenerator;
}
}
Still the ActionListener. Rename it.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SampleActionListener implements ActionListener {
private final DrawingCanvas canvas;
private final ShapeGenerator shapeGenerator;
public SampleActionListener(DrawingCanvas canvas, ShapeGenerator shapeGenerator) {
this.canvas = canvas;
this.shapeGenerator = shapeGenerator;
}
#Override
public void actionPerformed(ActionEvent event) {
this.canvas.setShapeGenerator(shapeGenerator);
}
}
The ShapeGenerator interface
public interface ShapeGenerator {
Shape getGeneratedShape(int x, int y);
}
And at least, the most stupid class : Shape
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public abstract class Shape extends JPanel implements java.awt.Shape {
protected int canvasX;
protected int canvasY;
public int getCanvasX() {
return canvasX;
}
public abstract java.awt.Shape getTrueShape();
public abstract void setCanvasX(int canvasX);
public int getCanvasY() {
return canvasY;
}
public abstract void setCanvasY(int canvasY);
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.draw(this.getTrueShape());
}
#Override
public Rectangle getBounds() {
return getTrueShape().getBounds();
}
#Override
public Rectangle2D getBounds2D() {
return getTrueShape().getBounds2D();
}
#Override
public boolean contains(int x, int y) {
return this.getTrueShape().contains(x, y);
}
#Override
public boolean contains(double x, double y) {
return this.getTrueShape().contains(x, y);
}
#Override
public boolean contains(Point2D p) {
return this.getTrueShape().contains(p);
}
#Override
public boolean contains(Point p) {
return this.getTrueShape().contains(p);
}
#Override
public boolean intersects(double x, double y, double w, double h) {
return this.getTrueShape().intersects(x, y, w, h);
}
#Override
public boolean intersects(Rectangle2D r) {
return this.getTrueShape().intersects(r);
}
#Override
public boolean contains(double x, double y, double w, double h) {
return this.getTrueShape().contains(x, y, w, h);
}
#Override
public boolean contains(Rectangle2D r) {
return this.getTrueShape().contains(r);
}
#Override
public PathIterator getPathIterator(AffineTransform at) {
return this.getTrueShape().getPathIterator(at);
}
#Override
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return this.getTrueShape().getPathIterator(at, flatness);
}
}
I have add the guava librairy, so, you will not find the Lists class. Add it to your project, use a other librairy or create a method to reverse your list.
Good luck and don't make something like that in the future !!! It's coding horror.
By the way, i came from France.

How paint() in a CLONE JPanel?

Anybody know how can I repaint in a clone JPanel. Im using CLONE, so I can REPAINT() one, and the other will do the same automatically.
My code only paints the original JPanel if I move the mouse in the original or in the clone panel,
but If I move the mouse in the clone panel, this jpanel doesn't paint.
Thanks in advance
CODE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ProcessorClone {
public static void main(String[] args) {
JFrame aWindow = new JFrame();
aWindow.setBounds(300, 200, 300, 100);
aWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Container content = aWindow.getContentP
aWindow.setVisible(true);
CardViewer panel02=new CardViewer();
CardViewer panel01= (CardViewer) panel02.clone();
aWindow.setLayout(new BorderLayout());
aWindow.add(panel01,BorderLayout.NORTH);
aWindow.add(panel02,BorderLayout.SOUTH);
panel01.setBackground(Color.RED);
panel02.setBackground(Color.blue);
panel01.repaint();
panel02.repaint();
panel01.validate();
panel02.validate();
}
}
class CardViewer extends JPanel implements MouseListener,MouseMotionListener, Cloneable {
/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel mContentPaneBorder;
private JPanel mContentPane;
private JButton FileButton=new JButton("AAA");
private Point p;
public CardViewer(){
super();
this.add(FileButton);
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("mouseClicked");
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
System.out.println("mousePressed");
p = null;
repaint();
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("mouseMoved");
p = e.getPoint();
this.repaint();
this.validate();
}
public void paint(Graphics g) {
System.out.println( g.getClass() );
if (p != null) {
Dimension d = getSize();
int xc = d.width / 2;
int yc = d.height / 2;
g.drawLine(p.x, p.y, p.x, p.y);
this.setBackground(Color.pink);
}
}
public Object clone () {
// First make exact bitwise copy
CardViewer copy = null;
try {
copy = (CardViewer)super.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return copy;
}
}
.clone() does not return a mirror of the JPanel but returns a copy of the object, so you really have 2 separate JPanel objects so actions in one will not automatically reflect in the other.
You could override all the actions in a component that inherits from JPanel with a reference to a .cloned() JPanel object and then route all methods to the other JPanel after calling super()

Categories