Im trying to add an object of the RedSquare class in to the JFrame in CatchMeV2 class. What is the problem?
public class CatchMeV2 implements ActionListener{
int width = 400;
int height = 450;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(400, 400);
frame.setTitle("CatchMe.V2");
RedSquare r = new RedSquare();
frame.add(r);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
public class RedSquare extends JPanel implements ActionListener {
int x = 20; int y = 20;
int velX = 4; int velY = 4;
public RedSquare(){
addActionListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.green);
g.fillRect(x, y, 50, 50);
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
x += velX;
y += velY;
if (x < 0) {
velX = 0;
x = 0;
}
if (x > 400 - 50) {
velX = 0;
x = 400 - 50;
}
if (y < 0) {
velY = 0;
y = 0;
}
if (y > 400 - 40) {
velY = 0;
y = 400 - 40;
}
repaint();
}
}
The actionPerformed method doesn't do anything. Can anyone help? Or is there an easy way to do this?
Background: I was trying to make a game by using one class. I did it but the problem was i could only take 1 key input at a time and it was lagging. And my teacher said that if I divided it into different classes it wouldn't lag. Is it true?
You cannot add non visual component to JPanel so you need to extend RedSquare class from component, for example JPanel and override paintComponent() method.
public class CatchMeV2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setTitle("CatchMe.V2");
RedSquare r = new RedSquare();
frame.setContentPane(r);
frame.setVisible(true);
}
}
class RedSquare extends JPanel implements ActionListener {
public RedSquare() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // don't forget to call super method
g.setColor(Color.green);
g.fillRect(20, 20, 50, 50);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
update>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
you can't use action performed for panel it's only for buttons or like that.if you want to do something with click on panel then you need to use implement mouselistner .and put action code inside mouseclick method .run this example
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
public class CatchMeV2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(400, 400);
frame.setTitle("CatchMe.V2");
RedSquare r = new RedSquare();
frame.add(r);
}
}
class RedSquare extends JPanel implements MouseListener {
int x = 20;
int y = 20;
int velX = 4;
int velY = 4;
public RedSquare() {
addMouseListener(this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(x, y, 50, 50);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("hi");
x += velX;
y += velY;
if (x < 0) {
velX = 0;
x = 0;
}
if (x > 400 - 50) {
velX = 0;
x = 400 - 50;
}
if (y < 0) {
velY = 0;
y = 0;
}
if (y > 400 - 40) {
velY = 0;
y = 400 - 40;
}
this.repaint();
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
at that time you only want to move square with mouse click so u can still use awt mouse event but when you use keys you have to use key binding
Related
I'm new to Eclipse, recently swapped from Bluej which ran my codes reliably. In Eclipse, it sometimes runs and sometimes just doesn't run the paint method and I'm not sure why. The same code was running this morning and now it decides to not run and I'm not sure what to do.
Main method:
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import Asset.Paddle;
import Asset.Puck;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.BorderLayout;
public class setup implements KeyListener, MouseListener, MouseMotionListener, Runnable {
int width = 100;
int height = 100;
int scale = 8;
public static setup setup;
JFrame frame;
JPanel main;
Graphic graphic;
Puck puck;
Paddle paddle1,paddle2;
boolean running, up = true, up2 = true;
boolean menu = false, b1, b2, b3;
int winSize;
public setup() {
puck = new Puck((width*scale)/2,(width*scale)/2,20,20);
paddle1 = new Paddle(width*scale/8-20,height*scale/2,20,100);
paddle2 = new Paddle(width*scale/8*7,height*scale/2,20,100);
frame();
}
public void frame() { //Frame setup
frame = new JFrame("Pong");
frame.setSize(width * scale,height * scale);
frame.setLayout(new BorderLayout());
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c1 = frame.getContentPane();
Dimension winSize = frame.getSize();
System.out.println(winSize);
graphic = new Graphic(puck,paddle1,paddle2);
graphic.addKeyListener(this);
graphic.addMouseListener(this);
graphic.addMouseMotionListener(this);
main = new JPanel();
main.setLayout(new BorderLayout());
main.setSize(width * scale,height * scale);
main.add(graphic,BorderLayout.CENTER);
start();
c1.add(main);
graphic.requestFocus();
}
public void start() { //running = true
new Thread(this).start();
running = true;
menu = true;
RENDER();
}
public void stop() {
running = false;
}
public void run() { //Game
while(running == true) {
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
if(puck.getY() < 0 || puck.getY() > height * scale) {
puck.reverseY();
}
paddle1.run();
paddle2.run();
puck.run();
RENDER();
}
}
public void RENDER() {
graphic.UPDATEPADDLE(paddle1,paddle2);
graphic.UPDATEPUCK(puck);
graphic.repaint();
}
public void keyPressed(KeyEvent evt) {
if(evt.getKeyCode() == 81) { // Q
paddle1.setYVel(-2);
up = true;
}
if(evt.getKeyCode() == 65) { // A
paddle1.setYVel(2);
up = false;
}
if(evt.getKeyCode() == 80) { // P
paddle2.setYVel(-2);
up2 = true;
}
if(evt.getKeyCode() == 76) {
paddle2.setYVel(2);
up2 = false;
}
}
public void keyReleased(KeyEvent evt) {
if(evt.getKeyCode() == 81 && up ) { // Q
paddle1.setYVel(0);
}
if(evt.getKeyCode() == 65 && !up) { // A
paddle1.setYVel(0);
}
if(evt.getKeyCode() == 80 && up2) { // P
paddle2.setYVel(0);
}
if(evt.getKeyCode() == 76 && !up2) { // L
paddle2.setYVel(0);
}
}
public void keyTyped(KeyEvent evt) {}
public void mouseClicked(MouseEvent e) {
// if(e.getX() > 375 && e.getX() < 375 + 200 && e.getY() > 400 && e.getY() < 400 + 50) {
// menu = false;
// System.out.println("clicked");
// graphic.UPDATEBUTTON(b1,b2,b3);
// graphic.UPDATEMENU(menu);
// start();
// graphic.repaint();
// }
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public static void main(String[] args) {
setup = new setup();
}
public void mouseDragged(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
if(e.getX() > 375 && e.getX() < 375 + 200 && e.getY() > 400 && e.getY() < 400 + 50) {
b1 = true;
graphic.UPDATEBUTTON(b1,b2,b3);
graphic.repaint();
}
else {
b1 = false;
graphic.UPDATEBUTTON(b1,b2,b3);
graphic.repaint();
}
}
}
Paddle:
package Asset;
public class Paddle {
double x, y, yVel, h, w;
public Paddle(double xx, double yy, int width, int height) {
x = xx;
y = yy;
h = height;
w = width;
}
public int getX() {
return (int)x;
}
public int getY() {
return (int)y;
}
public int getH() {
return (int)h;
}
public int getW() {
return (int)w;
}
public void setYVel(int yVelocity) {
yVel = yVelocity;
}
public void run() {
y += yVel;
if(y < 0) {
yVel = 0;
y = 0;
}
}
}
Puck:
package Asset;
public class Puck {
double x,y,w,h;
double xVel = 0;
double yVel = 3;
public Puck(double xx, double yy,int width,int height) {
x = xx;
y = yy;
w = width;
h = height;
x++;
}
public void reverseY() {
yVel *= -1;
}
public void reverseX() {
xVel *= -1;
}
public int getX() {
return (int)x;
}
public int getY() {
return (int)y;
}
public int getW() {
return (int)w;
}
public int getH() {
return (int)h;
}
public void run() {
x += xVel;
y += yVel;
}
}
Setup:
import java.awt.*;
import javax.swing.*;
import Asset.Paddle;
import Asset.Puck;
public class Graphic extends JPanel {
private static final long serialVersionUID = 2273791975624707192L;
Puck ppuck;
Paddle ppaddle1,ppaddle2;
boolean mmenu = true;
boolean bb1,bb2,bb3;
public Graphic(Puck puck,Paddle paddle1,Paddle paddle2) {
ppuck = puck;
ppaddle1 = paddle1;
ppaddle2 = paddle2;
}
public void UPDATEMENU(boolean menu) {
mmenu = menu;
}
public void UPDATEPADDLE(Paddle paddle1, Paddle paddle2) {
ppaddle1 = paddle1;
ppaddle2 = paddle2;
}
public void UPDATEPUCK(Puck puck) {
ppuck = puck;
}
public void UPDATEBUTTON(boolean b1,boolean b2, boolean b3) {
bb1 = b1;
bb2 = b2;
bb3 = b3;
}
public void paint (Graphics g) {
super.paint(g);
g.setColor(Color.black);
g.fillRect(0, 0, 1000, 1000);
if (mmenu) { //menu
if(bb1) {
g.setColor(Color.blue);
g.setFont(new Font("TimesRoman", Font.PLAIN, 50));
g.drawString("START", 390, 440);
}
else {
g.setColor(Color.white);
g.setFont(new Font("TimesRoman", Font.PLAIN, 50));
g.drawString("START", 390, 440);
}
}
else {
g.setColor(Color.white);
g.fillOval(ppuck.getX(), ppuck.getY(), ppuck.getW(), ppuck.getH());
g.fillRect(ppaddle1.getX(), ppaddle1.getY(), ppaddle1.getW(), ppaddle1.getH());
g.fillRect(ppaddle2.getX(), ppaddle2.getY(), ppaddle2.getW(), ppaddle2.getH());
}
}
}
So, two "basic" problems...
One, if you modify the UI after the frame is visible, you must call revalidate and repaint too trigger a layout and paint pass. A simpler solution, in your case, would be to call setVisible AFTER you've established the UI
public void frame() { //Frame setup
frame = new JFrame("Pong");
frame.setSize(width * scale, height * scale);
frame.setLayout(new BorderLayout());
frame.setLocationRelativeTo(null);
//frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c1 = frame.getContentPane();
//...
start();
c1.add(main);
graphic.requestFocus();
frame.setVisible(true);
}
Second...
This one's a little more complicated, but, you start your Thread and then update the state which it relies on to keep running
public void start() { //running = true
new Thread(this).start();
running = true;
menu = true;
RENDER();
}
While very, very unlikely, it's possible that the thread will inspect the state before you change it ... or because of the way the memory model works, won't see the change.
Better to set it before hand...
public void start() { //running = true
running = true;
new Thread(this).start();
menu = true;
RENDER();
}
You should also consider making it volatile
Having said that...
You're going around it all the wrong way.
To start with, don't try and do all the rendering for all the states in the single view, instead, use seperate views to different states (such as the start screen and the game screen).
You could then make use of CardLayout or simply overlay the containers onto of each other when you want to switch between them.
Next, you should avoid using KeyListener, it's troublesome at the best of times. Instead, make us of the key bindings API, then you won't need to post another question about why KeyListener has stopped working.
Next, Swing is single threaded and not thread safe. This means you should not be performing blocking or long running operations within the context of the Event Dispatching Thread or updating the UI or a state the UI depends on from outside of it.
Take a look at Concurrency in Swing for more details.
The simple solution in this case is probably to use a Swing Timer, see How to use Swing Timers for more details.
I would, personally, make the "game" panel responsible for setting up the input and rendering management, but that's me.
Good day, I'm new to StackOverflow and Java programming. I currently have a school project that needs multi threading and I just need your advice on how to fix my code. I have spent too much time looking for answers on how to create a moving multiple images using a thread. I knew I'm almost near to find the solution but I'm running out of time as the submission is fast approaching. I believed I'll be more efficient if I seek help from somehow who knows better in Java.
Many thanks in advance.
Below is my current code, and it seems that image is flickering while moving.
// Bounce.java
import javax.swing.JFrame;
public class Bounce {
public static void main(String args[]) {
myBall s = new myBall(10, 20, 2, 2);
myBall s1 = new myBall(100, 10, 2, 2);
myBall s2 = new myBall(40, 10, 2, 2);
JFrame f = new JFrame();
f.add(s);
f.add(s1);
f.add(s2);
f.setVisible(true);
f.setSize(600, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Moving Ball");
}
}
The next code is in separate file.
// myBall.java
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class myBall extends JPanel implements Runnable {
private Thread animator;
int x = 0, y = 0, velX = 2, velY = 2;
Timer t;
public myBall(int x, int y, int velX, int velY) {
JFrame jf = new JFrame();
jf.setSize(600,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(this);
jf.setVisible(true);
this.x = (int )(Math.random() * 560);
this.y = (int )(Math.random() * 360);
this.velX = velX;
this.velY = velY;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(ellipse);
}
public void cycle() {
if(x < 0 || x > 560) {
velX = -velX;
}
if(y < 0 || y > 360) {
velY = -velY;
}
x += velX;
y += velY;
System.out.println(x);
}
#Override
public void run() {
while(true) {
for (int i = 0; i < 600; i++) {
cycle();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
}
}
Here you go. I normally don't do this, but you asked nicely and your code was pretty clean, so I assumed you been working a lot on it.
public class Start {
public static void main(String args[]) {
JFrame f = new JFrame();
Gui gui = new Gui();
gui.addBalls();
f.add(gui);
f.setSize(600, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Moving Ball");
f.setVisible(true);
}
}
Class GUI:
public class Gui extends JPanel implements Runnable {
private Thread animator;
int x = 0, y = 0, velX = 2, velY = 2;
Timer t;
ArrayList<myBall> myBalls = new ArrayList<>();
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (myBall ball: myBalls) {
int x = ball.getX();
int y = ball.getY();
Ellipse2D ellipse = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(ellipse);
}
}
public void cycle() {
for (myBall ball: myBalls) {
int x = ball.getX();
int y = ball.getY();
if(x < 0 || x > 560) {
ball.reverseX();
}
if(y < 0 || y > 360) {
ball.reverseY();
}
ball.move();
System.out.println(x);
}
}
#Override
public void run() {
while(true) {
for (int i = 0; i < 600; i++) {
cycle();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
}
public void addBalls() {
for (int i = 0; i < 4; i++) {
int x = (int )(Math.random() * 560);
int y = (int )(Math.random() * 360);
int velX = -5;
int velY = 5;
myBalls.add(new myBall(x, y, velX, velY));
}
}
}
Class Ball:
public class myBall {
int x;
int y;
int velX;
int velY;
public myBall(int x, int y, int velX, int velY) {
this.x = (int )(Math.random() * 560);
this.y = (int )(Math.random() * 360);
this.velX = velX;
this.velY = velY;
}
public void move() {
x+=velX;
y+=velY;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void reverseX() {
velX = -velX;
}
public void reverseY() {
velY = -velY;
}
}
Basically, I'm developing a Java game where I have to make the troops move to the nearest hall inside the panel (like in Clash of Clans).
I have a BasePanel class that initializes 5 objects (Halls) that are randomly placed anywhere in the panel. The BasePanel has a mouselistener that when clicked, drops another object (Troop) to the x and y coordinates. The Troop object has an attribute that moves in a linear pattern. My problem is that the troop object just moves in a downward direction.
The question is how do I get the Troop object move to the closest Hall object in the BasePanel?
Here is my code:
import javax.swing.*;
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.event.*;
import javax.imageio.*;
import java.io.*;
import java.awt.image.*;
public class Test extends JFrame{
public static BasePanel panel1;
public static JButton baseClick, buttonClick, barbarian, archer, goblin;
public static int clicks=0, count1=10, count2=5, count3=7, hallCount=5, basePanelW=600, basePanelH=420;
public List<Troop> troops = new ArrayList<Troop>(20);
public List<Hall> halls = new ArrayList<Hall>(5);
public Thread gameThread;
Random rand = new Random();
float mouseX, mouseY;
float x = mouseX; // troop's center (x, y)
float y = mouseY;
double troopSpeedX = 1;
double troopSpeedY = 1;
float troopRadius = 5;
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test Test = new Test();
}
});
}
public void update() {
for (Troop troop : troops) {
troop.move(panel1);
}
}
class Hall{
int xVal = rand.nextInt(basePanelW);
int yVal = rand.nextInt(basePanelH);
public Hall(){}
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillOval(xVal, yVal, 50, 50);
}
public int getX(){
System.out.println("xVal: "+xVal);
return xVal;
}
public int getY(){
System.out.println("yVal: "+yVal);
return yVal;
}
}
class Troop{
float x = mouseX;
float y = mouseY;
double troopSpeedX = 1;
double troopSpeedY = 1;
float troopRadius = 5;
Hall h = new Hall();
public Troop(){}
public void paint(Graphics g){
g.setColor(Color.BLUE);
g.fillOval((int) (x - troopRadius), (int) (y - troopRadius), (int)(2 * troopRadius), (int)(2 * troopRadius));
}
public void move(JPanel panel){
x += troopSpeedX;
y += troopSpeedY;
if (x - troopRadius < 0) {
troopSpeedX = -troopSpeedX;
x = troopRadius;
}else if (x + troopRadius > basePanelW) {
troopSpeedX = -troopSpeedX;
x = basePanelW - troopRadius;
}else if (y - troopRadius < 0) {
troopSpeedY = -troopSpeedY;
y = troopRadius;
}else if (y + troopRadius > basePanelH) {
troopSpeedY = -troopSpeedY;
y = basePanelH - troopRadius;
}repaint();
}
}
public void start(){
gameThread = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {Thread.sleep(100/3);}catch(InterruptedException ex){}
}
}
}; gameThread.start();
}
class BasePanel extends JPanel{
private BufferedImage image;
BasePanel(){
setPreferredSize(new Dimension(basePanelW,basePanelH));
setBackground(Color.green);
while(hallCount>0){
halls.add(new Hall());
hallCount--;
}
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
mouseX = e.getX();
mouseY = e.getY();
clicks++;
}
public void mouseReleased(MouseEvent e){
troops.add(new Troop());
}
});
}
private void msgbox(String s){
JOptionPane.showMessageDialog(null, s);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Troop troop : troops){
troop.paint(g);
}
}
public void paint(Graphics g){
super.paint(g);
for (Hall hall : halls){
hall.paint(g);
}
}
}
public Test(){
panel1 = new BasePanel();
add(panel1, BorderLayout.CENTER);
setVisible(true);
setSize(700,420);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start();
}
}
I have the following code to show you:
public class Test extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5, this);
int x = 0, y = 0, velX = 0, velY = 0;
public Test()
{
tm.start(); //starts the timer
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paint(Graphics g)
{
super.paint(g);
ImageIcon s = new ImageIcon("C:\\Users\\Owner\\Pictures\\Stick.jpg");
s.paintIcon(this,g,x,y);
}
public void actionPerformed(ActionEvent e)
{
if (x < 0)
{
velX = 0;
x = 0;
}
if (x > 630)
{
velX = 0;
x = 630;
}
if(y < 0)
{
velY = 0;
y = 0;
}
if(y > 430)
{
velY = 0;
y = 430;
}
x = x + velX;
y = y + velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if (c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if(c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if(c == KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e)
{
velX = 0;
velY = 0;
}
public static void main(String[] args)
{
Test t = new Test();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(700, 600);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
jf.setVisible(true);
}
My problem is I whenever the user holds the right arrow on the keyboard it changes an image, when the user lets go it goes back the the default image. Please tell me how to do that. I think it is a series of if statements in the Graphics class then calling them to the key input but I'm not quite sure. I am also using Eclipse. Thank You.
Override paintComponent instead of paint. See Performing Custom Painting and Painting in AWT and Swing for more details
Use the key bindings API instead of KeyListener, it will cause you less issues. See How to Use Key Bindings for more details
Essentially, you could just have a Image as a class instance field, which was painted by the paintComponent method. When the key was pressed, you would change the image to the "move image" and when it was released, change it back to the "default image"
Updated with example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Mover {
public enum Direction {
LEFT, RIGHT, NONE;
}
public void setDirection(Direction direction);
public Direction getDirection();
}
public class TestPane extends JPanel implements Mover {
private BufferedImage left;
private BufferedImage right;
private BufferedImage stand;
private BufferedImage current;
private Direction direction = Direction.NONE;
private int xPos;
private int yPos;
public TestPane() {
try {
left = ImageIO.read(getClass().getResource("/Left.png"));
right = ImageIO.read(getClass().getResource("/Right.png"));
stand = ImageIO.read(getClass().getResource("/Stand.png"));
current = stand;
xPos = 100 - (current.getWidth() / 2);
yPos = 100 - (current.getHeight() / 2);
} catch (IOException exp) {
exp.printStackTrace();
}
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(this, Direction.LEFT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), new MoveAction(this, Direction.NONE));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(this, Direction.RIGHT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), new MoveAction(this, Direction.NONE));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updatePosition();
repaint();
}
});
timer.start();
}
protected void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(condition);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
public Direction getDirection() {
return direction;
}
#Override
public void setDirection(Direction direction) {
this.direction = direction;
}
protected void updatePosition() {
switch (getDirection()) {
case LEFT:
current = left;
xPos -= 1;
break;
case RIGHT:
current = right;
xPos += 1;
break;
case NONE:
current = stand;
break;
}
if (xPos < 0) {
xPos = 0;
current = stand;
} else if (xPos + current.getWidth() > getWidth()) {
current = stand;
xPos = getWidth() - current.getWidth();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(current, xPos, yPos, this);
g2d.dispose();
}
}
public class MoveAction extends AbstractAction {
private Mover mover;
private Mover.Direction direction;
public MoveAction(Mover mover, Mover.Direction direction) {
this.mover = mover;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
mover.setDirection(direction);
}
}
}
Here i have a code which draws a rectangle on the mouseClicked position using the paintComponent.I can get the output message but anything related to graphics and .draw() wont work.
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public final class testclass extends JFrame {
static JPanel p;
Timer t;
int x = 1;
int y = 1;
int xspeed = 1;
int yspeed = 1;
public testclass() {
initComponents();
this.setBounds(100, 300, 500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.start();
this.add(p);
}
public void initComponents() {
final ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
p.repaint();
}
};
t = new Timer(50, action);
p = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D gD = (Graphics2D) g;
moveBALL();
gD.drawOval(x, y, 25, 25);
p.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("a");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("b");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("c");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("d");
}
#Override
public void mouseClicked(MouseEvent e) {
gD.drawRect(e.getX(), e.getY(), 10, 60);
gD.setColor(Color.green);
System.out.println("clicked");
}
});
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > p.getWidth() - 20) {
x = p.getWidth() - 20;
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > p.getHeight() - 20) {
y = p.getHeight() - 20;
yspeed = -yspeed;
}
}
};
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new testclass().setVisible(true);
p.setBackground(Color.WHITE);
}
});
}
}
What is the proper way to implement a mouseListener() in this program?
Thanks.
Some suggestions on current code:
Watch class naming scheme i.e testclass should be TestClass or even better Test (but thats nit picking). All class names begin with capital letter and each new word thereafter is capitalized.
Dont extend JFrame unnecessarily.
Dont call setBounds on JFrame rather use appropriate LayoutManager and/or override getPreferredSize() of JPanel and return dimensions which fits its content.
Always call pack() on JFrame before setting it visible (taking above into consideration).
Use MouseAdapter vs MouseListener
Dont call moveBall() in paintComponent rather call it in your Timer which repaints the screen, not only slightly better design but we also should not do possibly long running tasks in paint methods.
As for your problem I think your logic is a bit skewed.
One approach would see the Rectangle (or Rectangle2D) get replaced by its own custom class (which will allow us to store attributes like color etc). Your ball would also have its own class which has the method moveBall() and its attributes like x and y position etc. On every repaint() your JPanel would call the method to move the ball, the JPanel itself could wrap the moveBall() in its own public method which we could than call from the timer which repaints the screen.
Here is an example of your code with above fixes implemented (please analyze it and if you have any questions let me know):
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.*;
public class Test {
private MyPanel p;
private Timer t;
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents();
frame.add(p);
frame.pack();
frame.setVisible(true);
t.start();
}
private void initComponents() {
final ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
p.moveEntities();//moves ball etc
p.repaint();
}
};
t = new Timer(50, action);
p = new MyPanel();
p.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN);
System.out.println("clicked");
}
});
p.setBackground(Color.WHITE);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class MyPanel extends JPanel {
int width = 300, height = 300;
ArrayList<MyRectangle> entities = new ArrayList<>();
MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height);
void addEntity(int x, int y, int w, int h, Color c) {
entities.add(new MyRectangle(x, y, w, h, c));
}
void moveEntities() {
ball.moveBALL();
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(ball.getColor());
g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height);
for (MyRectangle entity : entities) {
g2d.setColor(entity.getColor());
g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
class MyRectangle extends Rectangle2D.Double {
Color color;
public MyRectangle(double x, double y, double w, double h, Color c) {
super(x, y, w, h);
color = c;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
class MyBall extends Ellipse2D.Double {
int xspeed = 1;
int yspeed = 1;
Color color;
private final int maxWidth;
private final int maxHeight;
public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) {
super(x, y, w, h);
color = c;
this.width = w;//set width and height of Rectangle2D
this.height = h;
//set max width and height ball can move
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > maxWidth - ((int) getWidth() / 2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed
x = maxWidth - ((int) getWidth() / 2);
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > maxHeight - ((int) getHeight() / 2)) {
y = maxHeight - ((int) getHeight() / 2);
yspeed = -yspeed;
}
}
}
First of all the paint component is called every time swing needs to redraw the component.
And you are adding a new instance of mouse listener to the panel every time the paint is called.
Just move the line
p.addMouseListener(new MouseListener() {...}
out of the paint component, preferably after the initialization of the panel.
default template is
JPanel p = new JPanel(){
#Override
public void paintComponent(Graphics g) {
}
};
p.addMouseListener(new MouseListener() or new MouseAdapter()
//Your overridden methods
});
Hope this helps.