Hey guys i am trying to move a rectangle with arrow keys using keylistener in java. I got everything to work and imported everything but it is saying that the class name is not implemented in the non-abstract class "SoccerGame." I do not know what to do. I tried to make many changes to get it to work but it is still not functional. Are there any more packages I need to import or something? Hope you guys can help. Thanks.
// The "SoccerGame" class.
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
public class SoccerGame extends Applet implements KeyListener
{
int x = 200, y = 200;
public void init ()
{
this.requestFocus ();
addKeyListener (this);
setSize (800, 550);
} // init method
public void paint (Graphics g)
{
g.drawRect (20, 20, 340, 340);
g.fillRect (x, y, 20, 20);
} // paint method
public void keyPressed (KeyEvent e)
{
if (e.getKeyCode()==e.VK_UP)
{
y = y-10;
}
if (e.getKeyCode()==e.VK_DOWN)
{
y = y+10;
}
if (e.getKeyCode()==e.VK_LEFT)
{
x = x-10;
}
if (e.getKeyCode()==e.VK_RIGHT)
{
x = x+10;
}
repaint ();
}
public void keyReleased (KeyEvent e)
{
}
} // SoccerGame class
The code works fine after adding the missing public void keyTyped(KeyEvent arg0) {} to avoid compilation error.
Related
I am trying to make a simple game which displays circles on a frame and when clicked the circle should disappear. I am learning how Java Swing works and managed to draw a circle (Wow such an achievement) and figured out how events work. I added an mouseListener to the circle and when clicked for now I want a to get a console log that it has been clicked but the end result is not as expected. No matter where I click I always get the "click" console log. When I try to add a listener to a JButton for example I get the end result. Are events different for graphics?
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import java.awt.*;
import java.awt.event.*;
import java.sql.SQLOutput;
public class CirclePop {
JFrame frame;
Circle circle;
public static void main(String[] args) {
CirclePop circlePop = new CirclePop();
circlePop.drawFrame();
}
public void drawFrame() {
frame = new JFrame();
circle = new Circle();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(circle);
circle.addMouseListener(new Click());
frame.setSize(300, 300);
frame.setVisible(true);
}
class Click implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("Pressed");
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
}
import java.awt.*;
import javax.swing.*;
class Circle extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillOval(150, 140, 30, 30);
}
}
First of all, you may want to extend MouseAdapter instead of implementing MouseListener. This way you don't have "implement" all these empty methods.
Then, in your mousePressed method you just have to calculate if the click happened inside the circle. This is basically just Pythagoras:
static class ClickListener extends MouseAdapter {
private final Circle circle;
public ClickListener(Circle circle) {
this.circle = circle;
}
#Override
public void mousePressed(MouseEvent e) {
int centerX = circle.getCenterX();
int centerY = circle.getCenterY();
int radius = circle.getRadius();
int clickX = e.getX();
int clickY = e.getY();
// inside circle: (clickX - centerX)^2 + (clickY - centerY)^2 < radius^2
double xSquare = Math.pow(clickX - centerX, 2);
double ySquare = Math.pow(clickY - centerY, 2);
if (xSquare + ySquare < radius * radius) {
System.out.println("pressed");
}
}
}
I've added some fields to Circle class to get access to the properties you need for the calculation:
class Circle extends JPanel {
private final int radius = 30;
private final int centerX = 150;
private final int centerY = 140;
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillOval(centerX, centerY, radius, radius);
}
// getter, etc.
}
You have to implement the MouseListener interface indeed, and after a mouse click, you have to check whether the mouse position is contained in the region of your circle. You could do this manually, by comparing coordinates, but this could be a bit too much work. I think it's easier to rather create a Shape object(Infact this is a good time to learn about it since you're just starting out) that you fill with the respective color, and then just check whether the circle contains the mouse position.
Also, check out the Shape class docs when you've got some spare time.
I've gone ahead and made changes to your code, it now uses an instance of Shape class to create a circle.
Also, instead of implementing the MouseListener interface, I recommend extending MouseAdapter since you're not actually providing any meaningful implementation to any method of the interface except the mousePressed() method.
Lastly, notice the shape.contains(event.getPoint()) in the mousePressed() method, that is what does the trick for checking the coordinates.
The rest of the code should be familiar.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class CirclePop {
JFrame frame;
Circle circle;
public static void main(String[] args) {
CirclePop circlePop = new CirclePop();
circlePop.drawFrame();
}
public void drawFrame() {
frame = new JFrame();
circle = new Circle();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(circle);
circle.addMouseListener(new Click());
frame.setSize(300, 300);
frame.setVisible(true);
}
class Click extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (circle.shape.contains(e.getPoint())) {
System.out.println("Pressed");
}
}
}
}
class Circle extends JPanel {
Shape shape;
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
shape = new Ellipse2D.Double(150, 140, 30, 30);
g2.setColor(Color.red);
g2.fill(shape);
}
}
Okay, so, this isn't going to be short
Let's start with ....
frame = new JFrame();
circle = new Circle();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(circle);
circle.addMouseListener(new Click());
frame.setSize(300, 300);
frame.setVisible(true);
Okay, seems simple enough, but, one thing you've missed is the fact that JFrame, by default, uses a BorderLayout - this means, it will make the child component (and the centre/default position) fill all the available space of the frames viewable space
You can see this if you do something like...
frame = new JFrame();
circle = new Circle();
circle.setBackground(Color.RED);
You will now see that the Circle component occupies the entire frame, so when you click on it, you're clicking the Circle component itself.
This isn't bad, but, you might want to change tact a little. Instead of adding the MouseListener independently of the Circle, have the Circle component make use of its own MouseListener, for example...
class Circle extends JPanel {
public Circle() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// More to come...
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(150, 140, 30, 30);
}
}
This means you get to control much of the logic internally to the class, makes it easier to access some of the more critical information without needing to make a bunch of, potentially, dangerous casts.
So, now we just need to add the logic in to determine if the mouse was clicked within the desirable location or not...
public void mouseClicked(MouseEvent e) {
Point point = e.getPoint();
if (point.x >= 150 && point.x <= 150 + 30 && point.y >= 140 && point.y <= 140 + 30) {
System.out.println("You clicked me :(");
}
}
Okay, that's ... basic
We can simplify it a little and make use of the available functionality within the wider API by making use of the "shapes" API, for example...
class Circle extends JPanel {
private Ellipse2D dot = new Ellipse2D.Double(150, 140, 30, 30);
public Circle() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Point point = e.getPoint();
if (dot.contains(point)) {
System.out.println("You clicked me :(");
}
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.red);
g2d.fill(dot);
g2d.dispose();
}
}
The benefit of this, apart from contains, is we can change the position of the shape relatively easily and our if statement contains to work 🎉
I do, highly, recommend also having a look at
Performing Custom Painting
Painting in AWT and Swing
2D Graphics Trail
Working with Geometry
KeyListener doesn't work at all it's like it's not there, it shows the frame with the paddle but it doesn't move when arrowkey pressed , BUT my code worked properly on my friend's computer , i deleted and installed the last version of JDK and eclipse and nothing changed , i even compilated it with cmd and it doesn't work
edit : one in a 100 tries it works properly then the next time it returns to not working
the code is about a paddle that moves with arrowkeys
the Paddle class :
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
public class Paddle extends JPanel implements KeyListener{
private int x=900,y=280 ;
private int sx=20,sy=20 ;
private int valY=0;
public Paddle() {
setFocusable(true);
requestFocus();
addKeyListener(this);
}
public void paintComponent(Graphics g) {
draw(g);
update();
repaint();
}
public void draw(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, 1000, 1000);
g.setColor(Color.ORANGE);
g.fillRect(x, y, sx, sy);
}
public void update() {
this.y+=this.valY;
}
public void keyTyped(KeyEvent e) {
System.out.println("typed");
}
public void keyPressed(KeyEvent e) {
System.out.println("typed");
int c=e.getKeyCode();
if (c==KeyEvent.VK_UP){
this.valY=-1;
}
if(c==KeyEvent.VK_DOWN){
this.valY=1;
}
}
public void keyReleased(KeyEvent e) {
valY=0;
}
}
You are violating some rules of custom painting. The fact that it worked at all was mostly luck.
First, remove your call to repaint(). It is causing paintComponent to be called again, which calls repaint, which calls paintComponent, which calls repaint, etc. You are creating a very fast infinite loop which uses up most of Swing’s resources. Instead, call repaint() whenever you change the data on which your drawing relies.
Second, you are not accounting for the fact that painting occurs for many reasons. You don’t control most of them. paintComponent may be called when you move or resize the window, or even when the mouse moves over the window, or for a number of other reasons.
Since it is impossible to predict when the system will request that your class paint its contents, you must not change the state of your object in paintComponent. You must not call your update() method from paintComponent, either directly or indirectly.
The correct way to regularly update your state is to call your updating method from a Timer. For instance:
// Update every 250 milliseconds, that is, 4 times per second.
Timer timer = new Timer(250, e -> update());
timer.start();
Finally, whenever you override paintComponent, the first line of code needs to be a call to super.paintComponent(g);. If you don’t do that, you will eventually see strange painting artifacts. This is discussed in the Performing Custom Painting tutorial.
Your issue appears to have to do with the KeyListener and Focus. I am going to suggest an alternative technique. Use the InputMap/ActionMap for the panel.
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
panel.getInputMap().put(us, "UP");
panel.getActionMap().put("UP", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
//call what ever
}
});
When I do this, I don't have to request focus, I have a JFrame and a JPanel, as long as the JFrame is focus, then the respective actions get triggered by the keys.
Here is a complete example that moves a circle around a JPanel.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.EventQueue;
import java.awt.Color;
import javax.swing.KeyStroke;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class BallGame{
int x;
int y;
JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawOval(x-5, y-5, 10, 10);
}
};
public void start(){
JFrame frame = new JFrame();
frame.add(panel);
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
KeyStroke ds = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false);
KeyStroke ls = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);
KeyStroke rs = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
panel.getInputMap().put(us, "UP");
panel.getInputMap().put(ds, "DOWN");
panel.getInputMap().put(ls, "LEFT");
panel.getInputMap().put(rs, "RIGHT");
panel.getActionMap().put("UP", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
up();
}
});
panel.getActionMap().put("DOWN", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
down();
}
});
panel.getActionMap().put("LEFT", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
left();
}
});
panel.getActionMap().put("RIGHT", new AbstractAction(){
#Override
public void actionPerformed(ActionEvent evt){
right();
}
});
}
public void up(){
y = y - 5;
y = y<0? panel.getHeight() : y;
panel.repaint();
}
public void down(){
y = y + 5;
y = y>panel.getHeight() ? 0 : y;
panel.repaint();
}
public void left(){
x = x - 5;
x = x<0 ? panel.getWidth() : x;
panel.repaint();
}
public void right(){
x = x + 5;
x = x>panel.getWidth() ? 0 : x;
panel.repaint();
}
public static void main(String[] args){
BallGame bg = new BallGame();
EventQueue.invokeLater( bg::start );
}
}
Check out the api though because you can tune it to catch modifiers and when to trigger the action. In case you want to monitor when the key is pressed and when it is released etc.
this is my code. It worked for drawing a circle but I am having troubles drawing a triangle now.. A triangle should appear using mouse clicks but it is showing a triangle immediately after running the application. Please help. Thanks.
package mouse;
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.event.*;
import java.awt.geom.*;
public class triangle extends JFrame implements ActionListener, MouseListener {
int xx[]= {20, 50, 80};
int yy[]= {80, 30, 80};
public triangle () {
setSize(2000,2000);
addMouseListener(this);
}
public static void main(String[] args) {
//TODO code application logic here
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
triangle frame = new triangle();
frame.setVisible(true);
}
});
}
public void actionPerformed(ActionEvent ae) {
}
public void drawPolygon(int x, int y, int i)
{
Graphics g = this.getGraphics();
g.setColor(Color.BLACK);
g.drawPolygon(xx, yy, 3);
}
int x, y;
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void paint(Graphics g) {
drawPolygon(x, y, 3);
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
}``
The problem you have is that you override the paint method and therefore the drawPolygon method is already called in the initial painting of the JFrame.
For the effect you want to have you should avoid overriding the paint method and only use the drawPolygon method when the MouseListener is invoked.
This should look like this:
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
drawPolygon(x,y,3);
repaint();
}
In order to paint the triangle where you click with the mouse you need to add the current position to the original triangle coordinates like this:
public void drawPolygon(int x, int y, int i)
{
Graphics g = this.getGraphics();
g.setColor(Color.BLACK);
int[] drawx = {xx[0]+x,xx[1]+x,xx[2]+x};
int[] drawy = {yy[0]+y,yy[1]+y,yy[2]+y};
g.drawPolygon(drawx, drawy, i);
}
I hope this answers you question.
Some general remarks on programming:
You should definitely include a
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
otherwise you program won't terminate on closing the frame and keep on running.
It would also help the readability of your code if you avoid having everything in one class and split your code into several classes.
The MVC model is something that is a very good general guideline for designing class structures.
Here is the code.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Robot;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;
public class Paint extends JPanel implements MouseMotionListener, MouseListener {
public Paint() {
setBackground(Color.RED);
addMouseMotionListener(this);
addMouseListener(this);
}
private boolean clicked = false;
public void paintComponent (Graphics g) {
super.paintComponent(g);
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
int x = (int) b.getX() - 3;
int y = (int) b.getY() - 23;
if (clicked) {
g.drawLine(x, y-5000, x,y+5000);
g.drawLine(x+5000,y,x-5000,y);
g.setColor(Color.white);
}
g.drawLine(x, y-5000, x,y+5000);
g.drawLine(x+5000,y,x-5000,y);
g.setColor(Color.black);
// . . .
}
#Override
public void mouseDragged(MouseEvent e) {
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
repaint();
}
#Override
public void mouseClicked(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
}
#Override
public void mousePressed(MouseEvent e) {
clicked = true;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
clicked = false;
repaint();
}
}
public class Frame extends JFrame {
public Frame() {
this.setSize(500,500);
this.setTitle("Test painting");
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
Paint panel = new Paint();
this.add(panel);
this.setVisible(true);
}
public static void main (String[] args) {
new Frame();
}
}
When I run the program, it looks like it works fine when the application is in the default position, but once I move the applet to where I like on the screen, the lines don't maintain the current mouse position on screen.
Can someone show me where I've gone wrong or how to fix this?
Painting is done from the context of the component. The Graphics context for any given component is translated so that the top, left corner is 0x0.
MouseInfo.getPointerInfo().getLocation() is returning the location of the mouse on the screen, not the position relative to the component.
While there is a way to fix it, a better solution would be to simply use a MouseMotionListener instead. The MouseEvent sent to this method has already been translated to the component coordinate space...
public void mouseMoved(MouseEvent me) {
myPoint = me.getPoint();
}
Then in you paintComponent method, simple refer to myPoint instead of trying to use MouseInfo
I think that you will be better off to change your class's state in the MouseAdapter, call repaint() and then have your paintComponent(...) method use this state to help it draw. This seems cleaner and safer to me than using MouseInfo in paintComponent(...).
Other than that, if you need more specific help, consider
telling us more about what it is exactly you're trying to do and how your program isn't working.
creating and posting an sscce, a small compilable and runnable program that demonstrates your problem for us.
Thanks for checking out this Question. I think I've just about scratched through my skull in frustration.
So what I've got is a 'JFrame' containing a 'JPanel'. The 'JPanel' contains a little colored Square which is supposed to move X pixels whenever I click the window.
Well, essentially everything behaves as it should, with one exception. When the blue square moves to the right, it leaves a trail of other squares behind it. It is not supposed to leave the trail, however, when I re-size the window, the trail vanishes.
Catalyst.java
package Prototype;
import java.awt.*;
public class Catalyst {
public static void main(String[] args){
World theWorldInstance = new World("Prototype", 100,100, 600,100); /*title,xpos,ypos,width,height*/
}
}
World.java
package Prototype;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class World extends JFrame {
Level mainPanel;
public World(String title, int x, int y, int width, int height) {
setTitle(title);
setBounds(x,y,width,height);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBackground(new Color(0x00000000));
initLevel();
}
public void initLevel(){
mainPanel = new Level();
Container visibleArea = getContentPane();
visibleArea.add(mainPanel);
setVisible(true);
add(mainPanel);
}
}
Level.java
package Prototype;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Level extends JPanel implements MouseListener, ActionListener {
Square x;
public Level() {
System.out.println("This is working correctly[JPANEL Cons]");
addMouseListener(this);
x = new Square();
}
public void paintComponent(Graphics g){
x.draw(g);
}
public void actionPerformed(ActionEvent e){
}
public void mousePressed(MouseEvent e){
requestFocus();
x.move();
repaint();
System.out.println("Focus Acquired");
}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
}
Square.java
package Prototype;
import java.awt.*;
public class Square {
private Point position;
private int size;
private final int displacement;
public Square(){
position = new Point(10,10);
size = 20;
displacement = 5;
}
public void draw(Graphics g){
g.setColor(Color.blue);
g.fillRect(position.x-(size/2), position.y-(size/2), size,size );
g.setColor(Color.black);
g.drawRect(position.x-(size/2), position.y-(size/2), size,size );
}
public void move() {
position.x += displacement;
}
}
Those are all my files. I hope I've phrased everything properly and provided all the content required. Whenever I've done something similar in the past this has never happened. I assume I'm missing something small, or I've done something stupid. If you can help me, thanks in advance!
There's another way of doing this. You can simply call the parent object's paintComponent method to clear the panel.
Add this to your constructor in Level :
this.setBackground(Color.BLACK);
And this as the first call in paintComponent:
super.paintComponent(g);
You can use g.clearRect(x, y, width, height), and provide the said coordinates, where you want the painting to be cleared from. Or you can give the dimensions of whole of the JPanel/JComponent where you are drawing, though doing this keep one thing in mind, that the said drawing is not a heavy work, else too much of cleaning will put extra burden on the painting calls.