I am trying to animate a circle in Java. I want it to move every time I press a key, but it is not working. Is there a problem with the way I am drawing the circle? Am I forgetting a repaint() somewhere.
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JPanel implements KeyListener {
int x = 300, y = 300;
public Main() {
super();
}
public void paintComponent(Graphics g) {
g.drawOval(x, y, 300, 300);
}
#Override
public void keyPressed(KeyEvent e) {
x++;
y++;
repaint();
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(1200, 800);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.add(new Main());
f.setVisible(true);
}
}
Don't use KeyListener, honestly, make use of the Key Bindings API instead, which has been designed to resolve the issues which KeyListener creates.
paintComponent in JPanel does an important job, you are expected to call it's super method before doing any custom painting.
See Painting in AWT and Swing and Performing Custom Painting for more details
You should also make an effort to initialise you UI from within the context of the Event Dispatching Thread, this solves a number of known issues on some platforms, see Initial Threads for more details
You are not very far off. First, you need to actually add a listener for your key events.
f.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
m.keyPressed(e);
}
});
Second, you'll notice this uses 'm'. That is a reference to your Main object.
Change:
f.add(new Main());
to:
Main m = new Main();
f.add(m);
Now it should work!
Related
I was working on this lab in class and when I tried changing the background color it would stay at its default of white can someone please explain where I my programming went wrong.
import javax.swing.*;
import java.awt.*;
public class DemoPoly extends JFrame {
// constructor
public DemoPoly() {
// defines Frame characteristics
int size = 300;
setSize(size,size);
setTitle("a random window");
getContentPane().setBackground(Color.red);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main (String[] args){
// instantiates a JFrame
// exits on close (opional)
JFrame object = new DemoPoly();
}
public void paint (Graphics g){
// This provides the Graphics object g, where
// you are going to use you graphics primitive
// to paint on the content pane of the frame.
int[] arr = {0,100,100,0};
int[] yarr = {0,0,100,100};
Square object = new Square(arr,yarr,Color.red);
AbstractPolygon randSquare = new Square(arr, yarr, Color.red);
}
I see a couple of problems in your code:
Extending JFrame is like saying your class is a JFrame, JFrame is a rigid container, instead create your GUI based on JPanels. See Java Swing extends JFrame vs calling it inside of class for more information.
You're breaking the paint chain by removing the super.paint(g) call on the paint(...) method. When changing your GUI to extend JPanel instead of JFrame you should use the paintComponent(...) method instead. Take the Lesson: Performing Custom Painting in Swing.
You forgot to add #Override notation on the paint(...) method.
You're not placing your program on the Event Dispatch Thread (EDT) which could cause threading issues.
You can solve this by changing your main() method like this:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//Your constructor here
}
});
}
Instead of setting the JFrame size, override the getPreferredSize() method and call pack(). See Should I setPreferred|Maximum|MiniumSize in Java Swing?. The general consensus says yes.
Your problem gets solved by adding
super.paint(g);
on the paint(...) method:
#Override
public void paint(Graphics g) {
super.paint(g); //Never remove this
//Your code goes here
}
With all the above recommendations taken into account, your code should look like this now:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class DemoPoly {
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DemoPoly().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
CustomPanel cp = new CustomPanel();
cp.setBackground(Color.RED);
frame.add(cp);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
class CustomPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
Which produces this output (and is the same output that you'll get with your current code but better because it gives you more control over your components)
I'm don't understand your question. But here is code for change your background to RED;
public class DemoPoly extends JFrame {
public DemoPoly() {
// defines Frame characteristics
int size = 300;
setSize(size, size);
setTitle("a random window");
//change background here
getContentPane().setBackground(Color.red);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
// instantiates a JFrame
// exits on close (opional)
JFrame object = new DemoPoly();
}
}
Your code is well. Maybe use #override in your paint method.
I am not sure why the mouse events set by my mouse listener are not affecting whether or not the hat is drawn. The variable "mouseInside" seems not to be affected by the mouse events. How do I change the variable to false with the mouse events?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
public class EyesOpen extends JPanel{
private Ellipse2D.Double head;
private Ellipse2D.Double eyeOne;
private Ellipse2D.Double eyeTwo;
private Rectangle2D.Double hatBody;
boolean mouseInside;
public EyesOpen(){
this.setFocusable(true);
this.requestFocus();
this.setPreferredSize(new Dimension(500,500));
head = new Ellipse2D.Double(180,180,140,140);
eyeOne = new Ellipse2D.Double(220,220,20,20);
eyeTwo = new Ellipse2D.Double(260,220,20,20);
hatBody = new Rectangle2D.Double(170,180,160,20);
class MyMouseListener implements MouseListener{
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e){
mouseInside=true;
}
public void mouseExited(MouseEvent e){
mouseInside=false;
}
public void mousePressed(MouseEvent e){
}
public void mouseReleased(MouseEvent e){
}
}
this.addMouseListener(new MyMouseListener());
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(Color.BLUE);
g2.fill(head);
g2.setPaint(Color.BLACK);
g2.fill(eyeOne);
g2.setPaint(Color.BLACK);
g2.fill(eyeTwo);
if(mouseInside=true){
g2.setPaint(Color.BLACK);
g2.fill(hatBody);}
}
public static void main(String[] args){
JFrame f = new JFrame("Head");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLayout(new FlowLayout());
f.add(new EyesOpen());
f.pack();
f.setVisible(true);
}
}
Don't forget to call repaint() after changing the boolean.
To be precise, you could specify that it is the drawing component's method that gets called via EyesOpen.this.repaint();, but this isn't absolutely necessary in this current program (I don't think).
Other nitpicks:
The paintComponent(...) method should be specified as protected not public. No sense in exposing it any more than it needs to be exposed.
Don't forget to use the #Override annotation any time that you think that you're overriding a method. While it may not matter with this program, it will save your behind in the future.
You will want to start your GUI on the Swing thread in your main method by placing your JFrame creation code inside of a Runnable and then queuing that Runnable onto the event queue by placing it into a SwingUtilities.invokeLater(/** Your Runnable Goes Here **/);
So I am trying to implement a mouse listener into my program, I got the mouseListener to work but not the graphics. I am trying to find a way to draw a blue circle every time the mouse is clicked on the JPANEL, the only problem is I can not seem to get a good call for the Graphics (that I have tried to name g).
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
class moveItMon extends JPanel implements MouseListener{
public moveItMon() {
this.setPreferredSize(new Dimension(500, 500));
addMouseListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void mouseClicked(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e) {
movetehMon(e);
}
public void movetehMon(MouseEvent e){
int x = e.getX();
int y = e.getY();
System.out.println("(" + x + "," + y + ")");
paintMon(x,y);
}
public void paintMon( int x, int y){
Graphics g = new Graphics();
g.setColor(Color.WHITE);
g.clearRect(0,0,500,500);
g.setColor(Color.BLUE);
g.fillOval(x,y,20,20);
}
public static void main(String[] s) {
JFrame f = new JFrame("moveItMon");
f.getContentPane().add(new moveItMon());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
Graphics g = new Graphics(); isn't going to work (as I'm sure you're aware) as the class is abstract.
Custom painting in Swing is done by overriding the paintComponent of a component that extends from JComponent (like JPanel) and using the supplied Graphics context to paint to.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
You should also beware that painting is a destructive process, meaning that each time paintComponent is called, you are expected to update everything that you need painted.
I've been reading the java documentation and am trying to understand key listeners and their uses. I managed to make a simple program where 'w' and 's' toggled the background colour, however when I tried to make them move a painted ball they stopped responding. I am fairly sure it isn't a painting issue as I read through the JavaDocs common painting issues. I've set the JFrame as focuseable (or at least I think I have). If anyone could point me In the right direction it would be greatly appreciated.
Here is the main class
import javax.swing.JFrame;
import java.awt.EventQueue;
public class frame {
public static void main(String[] args){
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
showGui();
}
});
}
public static void showGui(){
JFrame f = new JFrame("Testing..");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setFocusable(true);
f.add(new Gui());
f.setSize(300,300);
f.setVisible(true);
}
}
and the Gui/KeyListener class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Gui extends JPanel {
public Gui(){
HandlerClass handle = new HandlerClass();
setBorder(BorderFactory.createLineBorder(Color.black));
addKeyListener(handle);
}
int x = 30;
int y = 30;
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.BLUE);
g.fillRect(x, y, 20, 20);
}
private class HandlerClass implements KeyListener{
public void keyTyped(KeyEvent e) {
switch (e.getKeyChar()){
case 'w':
repaint(x,y+1, 20,20);
break;
case 's':
repaint(x,y-1, 20,20);
System.out.println("testing if this fires");
break;
}
}
public void keyPressed(KeyEvent e) {
//todo
}
public void keyReleased(KeyEvent e) {
//todo
}
}
}
Any pointings in the right direction would be very helpful, thank you.
KeyListener will only respond to key events when the component it is attached to is focusable and has focus.
JPanel by default does not meet either of these requirements (by default, it is not focusable).
For these reasons, it is not recommended that you use KeyListener, but instead use Key Bindings, which has the ability to overcome these issues
If you've searched this site at all, you'll know this solution already: don't use KeyListeners but rather Key Bindings. If you haven't searched this site, well you should have done this before asking the question.
e.g.: a previous answer of mine with example code
repaint(x,y+1, 20,20);
You are painting y slightly higher, however you are not actually changing y. Try:
repaint(x,++y, 20,20);
The same applies (in the other direction) for your other listener.
am doing that program to paint the mouse location in a panel , the program works fine but after like 10 seconds it stops painting the points... any help?
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class Draw extends JPanel {
public static int newx;
public static int newy;
public void paint(Graphics g) {
Mouse mouse = new Mouse();
mouse.start();
int newx = mouse.x;
int newy = mouse.y;
g.setColor(Color.blue);
g.drawLine(newx, newy, newx, newy);
repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.white);
frame.setSize(2000,2000 );
frame.setVisible(true);
frame.getContentPane().add(new Draw());
frame.revalidate();
frame.getContentPane().repaint();
}
}
public void paint(Graphics g) should be public void paintComponent(Graphics g).
And you isn't supposed to call repaint() inside this method.
You should add an mouse listener outside this method, too.
An adapted example from Java Tutorials
public class MouseMotionEventDemo extends JPanel
implements MouseMotionListener {
//...in initialization code:
//Register for mouse events on blankArea and panel.
blankArea.addMouseMotionListener(this);
addMouseMotionListener(this);
...
}
public void mouseMoved(MouseEvent e) {
Point point = e.getPoint();
updatePanel(point); //create this method to call repaint() on JPanel.
}
public void mouseDragged(MouseEvent e) {
}
}
}
You call repaint within the paint method, causing an infinite loop. Swing Timers are preferred for running periodic updates on components.
For custom painting in Swing the method paintComponent rather than paint should be overridden not forgetting to call super.paintComponent.