How to clear in jframe - java

I have a situation where I'm moving a ball. However, after struggling with the queue that repaint() places paintComponent(Graphics g) in. I resorted to using paintImmediately. The problem now is that without access to super.paintComponent(g), I don't know how to clear the canvas each time before I paint. So one possible answer to my question would be a way to clear the canvas by itself. I also found that Threads could be a possible solution but after a great many attempts to implement that idea, I still don't understand that so if someone could show correct implementation for that I would be very grateful.
Here is my code:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
public class PhysicsEngine extends JPanel {
double x, y;
JPanel pan;
JButton b1;
JButton b2;
JButton b3;
JButton b4;
JButton b5;
public static void main(String[] args) {
JFrame frame = new JFrame("Ball Engine");
PhysicsEngine gui = new PhysicsEngine();
frame.add(gui, BorderLayout.CENTER);
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public PhysicsEngine() {
b1 = new JButton("1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
startFirst();
} catch (InterruptedException exception) {
}
}
});
this.add(b1);
b2 = new JButton("2");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startSecond();
} catch (InterruptedException exception) {
}
}
});
this.add(b2);
b3 = new JButton("3");
b3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startThird();
} catch (InterruptedException exception) {
}
}
});
this.add(b3);
b4 = new JButton("4");
b4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startFourth();
} catch (InterruptedException exception) {
}
}
});
this.add(b4);
b5 = new JButton("5");
b5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startFifth();
} catch (InterruptedException exception) {
}
}
});
this.add(b5);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("" + y);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval((int) x, (int) y, 30, 30);
}
public void startFirst() throws InterruptedException {
x = 300;
y = 80;
// xPos= 0*t*t + 0*t + 300 this is constant at 300
for(int t = 1; t<70;t++){
y = .1 * t * t + 0 * t + 80; // parametric equation for y
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startSecond() throws InterruptedException {
x = 300;
y = 550;
for (int t = 1;t<150; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
y = .1 * t * t - 15 * t + 550; // parametric equation for y
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startThird() throws InterruptedException {
y = 550;
x = 50;
for (int t = 1;t<150; t++) {
y = .1 * t * t - 15 * t + 550; // parametric equation for y
x = 0 * t * t + 3 * t + 50; // parametric equation for x
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startFourth() throws InterruptedException {
y = 50;
x = -4;
for (int t = 1;t<110; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
y = .001*t * t * t + 50; // given parametric equation for y
x = t - 4; // given parametric equation for x
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
public void startFifth() throws InterruptedException {
for (int t = 1; t < 130 /* goes for 1.5 seconds */; t++) {
y = 200 * Math.sin(.05*t) + 300; // given parametric equation for y
x = 200 * Math.cos(.05*t) + 300; // given parametric equation for x
repaint();
paintImmediately((int)x, (int)y, 30, 30);
Thread.sleep(10);
}
}
}

Your problem isn't the "paint queue", it's the fact that you're violating the single threaded nature of the API, by calling Thread.sleep within the context of the EDT.
Instead of using for-loops with Thread.sleep in them, you should make use of a Swing Timer which updates the state of the variables paintComponent relies on (and call repaint)
Swing Timer can be thought of a pseudo loop, whose ActionListener is called within the context of the EDT, making it safe to update the UI from
Start by having a look at Concurrency in Swing and How to Use Swing Timers for more details
As a conceptual example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
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 class TestPane extends JPanel {
private PhysicsPane physicsPane;
public TestPane() {
physicsPane = new PhysicsPane();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
JButton b1 = new JButton("1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
startFirst();
}
});
this.add(b1, gbc);
this.add(physicsPane, gbc);
}
protected void startFirst() {
physicsPane.startFirst();
}
}
public class PhysicsPane extends JPanel {
private Timer timer;
private double xPos, yPos;
private int tick;
public PhysicsPane() {
setBackground(Color.BLUE);
}
protected void stopTimer() {
if (timer == null) {
return;
}
timer.stop();
timer = null;
}
public void startFirst() {
stopTimer();
xPos = 300;
yPos = 500;
tick = 0;
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (tick >= 150) {
stopTimer();
return;
}
yPos = .1 * tick * tick - 15 * tick + 550;
tick++;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.fillOval((int) xPos, (int) yPos, 30, 30);
g2d.dispose();
}
}
}

Related

Overrided paint method not being called after repaint is

My problem is essentially creating a physics engine with a few different scenarios. I would like to consolidate the different scenarios into one window by having buttons that run each individually. The frame works properly and the buttons show up and can be pressed; however, that print line in the pain method is never happening and from there I concluded that paint is not being called even after repaint is. I understand that they are not the same but I don't understand why paint isn't being accessed in this instance compared to others.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.JButton;
public class PhysicsEngine extends JPanel{
double x ,y;
JFrame frame;
JPanel pan;
JButton b1;
JButton b2;
JButton b3;
JButton b4;
JButton b5;
public static void main(String[] args){
PhysicsEngine gui = new PhysicsEngine();
}
public PhysicsEngine(){
frame = new JFrame("Ball Engine");
pan = new JPanel();
frame.add(pan);
b1 = new JButton("1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event){
try{
startFirst();
}
catch(InterruptedException exception){}
}
});
pan.add(b1);
b2 = new JButton("2");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
try{
startSecond();
}
catch(InterruptedException exception){}
}
});
pan.add(b2);
b3 = new JButton("3");
b3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
try{
startThird();
}
catch(InterruptedException exception){}
}
});
pan.add(b3);
b4 = new JButton("4");
b4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
try{
startFourth();
}
catch(InterruptedException exception){}
}
});
pan.add(b4);
b5 = new JButton("5");
b5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
try{
startFifth();
}
catch(InterruptedException exception){}
}
});
pan.add(b5);
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
System.out.println(""+y);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval((int)x, (int)y, 30, 30);
}
public void startFirst() throws InterruptedException{
x = 300;
for(int t = 1;;t++){
//xPos= 0*t*t + 0*t + 300 this is constant at 300
if(y>=615) break; //stops the loop when the ball is off the screen
y = .1*t*t + 0*t + 80; //parametric equation for y
repaint();
Thread.sleep(10);
}
}
public void startSecond() throws InterruptedException{
x = 300;
for(int t = 1;;t++){
//xPos= 0*t*t + 0*t + 300 this is constant at 300
if(y>=615) break; //stops the loop when the ball is off the screen
y = .1*t*t - 10*t + 550; //parametric equation for y
repaint();
Thread.sleep(10);
}
}
public void startThird() throws InterruptedException{
for(int t = 1;;t++){
if(y>=615||x>=615) break; //stops the loop when the ball is off the screen
y = .1*t*t - 10*t + 550; //parametric equation for y
x = 0*t*t + 5*t + 50; //parametric equation for x
repaint();
Thread.sleep(10);
}
}
public void startFourth() throws InterruptedException{
for(int t = 1;;t++){
//xPos= 0*t*t + 0*t + 300 this is constant at 300
if(y>=615||x>=615) break; //stops the loop when the ball is off the screen
y = t*t*t + 50; //given parametric equation for y
x = t - 4; //given parametric equation for x
repaint();
Thread.sleep(10);
}
}
public void startFifth() throws InterruptedException{
for(int t = 1;t<500 /* goes for 5 seconds */;t++){
y = 200*Math.sin(t) + 300; //given parametric equation for y
x = 200*Math.cos(t) + 300; //given parametric equation for x
repaint();
Thread.sleep(10);
}
}
}
The basic problem is you are overriding the paint() method of the PhysicsEngine class. But you never add an instance of this class to the frame.
However, the bigger problem is the structure of your class. Your main class should not be extending a JPanel just so you can create a JFrame. The logic for creating the frame should be in the main() method and then your PysicsEngine panel should contain all the components you want to build for your frame. Also, custom painting should be done by overriding the paintComponent(...) method, not the paint() method.
Read the section from the Swing tutorial on Custom Painting for basic painting information and demos.
Then you can look at other sections in the tutorial for a better way to structure your code. For example the ButtonDemo code found in the How to Use Buttons tutorial will show you how to extend a JPanel and add buttons to it.
repaint() stores a request for refreshing a component, request that will be executed by the GUI thread later on. But a component will be refreshed only if it is visible on screen, alas your PhysicsEngine class doesn't seem to be used as a visible component in some visible GUI hierarchy.
Your paint method should be paintComponent and also should call the paintComponent method of super class.
And you don't add the PhysicsEngine JPanel into the JFrame, and it is very bad approach to create a JFrame in the constructor of JPanel subclass. I create a JFrame in the main method and create a object of PhysicsEngine (JPanel Subclass) and add it into the JFrame. I add the buttons by using this which reference to the PhysicsEngine (JPanel subclass) object.
Here is the working code:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
public class PhysicsEngine extends JPanel {
double x, y;
JPanel pan;
JButton b1;
JButton b2;
JButton b3;
JButton b4;
JButton b5;
public static void main(String[] args) {
JFrame frame = new JFrame("Ball Engine");
PhysicsEngine gui = new PhysicsEngine();
frame.add(gui, BorderLayout.CENTER);
frame.setSize(600, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public PhysicsEngine() {
b1 = new JButton("1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
startFirst();
} catch (InterruptedException exception) {
}
}
});
this.add(b1);
b2 = new JButton("2");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startSecond();
} catch (InterruptedException exception) {
}
}
});
this.add(b2);
b3 = new JButton("3");
b3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startThird();
} catch (InterruptedException exception) {
}
}
});
this.add(b3);
b4 = new JButton("4");
b4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startFourth();
} catch (InterruptedException exception) {
}
}
});
this.add(b4);
b5 = new JButton("5");
b5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
startFifth();
} catch (InterruptedException exception) {
}
}
});
this.add(b5);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("" + y);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval((int) x, (int) y, 30, 30);
}
public void startFirst() throws InterruptedException {
x = 300;
for (int t = 1;; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
if (y >= 615)
break; // stops the loop when the ball is off the screen
y = .1 * t * t + 0 * t + 80; // parametric equation for y
repaint();
Thread.sleep(10);
}
}
public void startSecond() throws InterruptedException {
x = 300;
for (int t = 1;; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
if (y >= 615)
break; // stops the loop when the ball is off the screen
y = .1 * t * t - 10 * t + 550; // parametric equation for y
repaint();
Thread.sleep(10);
}
}
public void startThird() throws InterruptedException {
for (int t = 1;; t++) {
if (y >= 615 || x >= 615)
break; // stops the loop when the ball is off the screen
y = .1 * t * t - 10 * t + 550; // parametric equation for y
x = 0 * t * t + 5 * t + 50; // parametric equation for x
repaint();
Thread.sleep(10);
}
}
public void startFourth() throws InterruptedException {
for (int t = 1;; t++) {
// xPos= 0*t*t + 0*t + 300 this is constant at 300
if (y >= 615 || x >= 615)
break; // stops the loop when the ball is off the screen
y = t * t * t + 50; // given parametric equation for y
x = t - 4; // given parametric equation for x
repaint();
Thread.sleep(10);
}
}
public void startFifth() throws InterruptedException {
for (int t = 1; t < 500 /* goes for 5 seconds */; t++) {
y = 200 * Math.sin(t) + 300; // given parametric equation for y
x = 200 * Math.cos(t) + 300; // given parametric equation for x
repaint();
Thread.sleep(10);
}
}
}

How to draw an array of Graphics

OK so i'm working on a school project (little animation) and I am currently trying to make rain. I'm not sure how I would go about drawing individual "drops" using JPanel. My Code so far:
Main Class:
public class RainPanel extends JPanel {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
new RainPanel();
}
private final int WIDTH = 800, HEIGHT = 800;
Drop drop;
public RainPanel() {
init();
}
public void init() {
JFrame frame = new JFrame("Rain");
JPanel drop = new Drop();
frame.setVisible(true);
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(drop);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drop.paint(g);
}
Drop class:
public class Drop extends JPanel implements ActionListener{
private static final long serialVersionUID = 1L;
int x,y;
int yVel = 2;
Timer t = new Timer(5, this);
Random r = new Random();
ArrayList<Drop> DropArray;
public Drop() {
x = r.nextInt(800);
y = r.nextInt(800);
t.start();
}
public void paint(Graphics g) {
super.paintComponent(g);
DropArray = new ArrayList<>(100);
for (int i = 0; i < DropArray.size(); i++) {
DropArray.add(new Drop());
}
g.setColor(Color.BLUE);
g.fillRect(x, y, 3, 15);
}
public void update() {
y += yVel;
if (y > 800)
y = r.nextInt(800);
}
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
I understand if you might be cringing hard right now (I'm fairly new to graphics coding and mostly familiar with Java itself). All i'm getting drawn currently is a single rain drop. Any suggestions are appreciated.
Don't call super.paintComponent from within paint, you're breaking the paint chain which could cause no end of issues. Override paintComponent directly instead
You shouldn't be modifying the state of a component or anything the component relies on from within any paint method, paint can be called a number of times in quick succession and this can cause no end of issues
Component based animation is not a simple task and unless you really, really need it, you should try and avoid it. Instead, write a class which is "paintable", which you can call from your paintComponent method
For example..
import java.awt.Color;
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.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RainDropsKeepFalling {
public static void main(String[] args) {
new RainDropsKeepFalling();
}
public RainDropsKeepFalling() {
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 RainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RainPane extends JPanel {
private List<Drop> drops = new ArrayList<>(100);
public RainPane() {
for (int index = 0; index < 100; index++) {
drops.add(new Drop(getPreferredSize()));
}
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Drop drop : drops) {
drop.update(getSize());
repaint();
}
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Drop drop : drops) {
Graphics2D g2d = (Graphics2D) g.create();
drop.paint(g2d);
g2d.dispose();
}
}
}
protected static final Random random = new Random();
public static class Drop {
private double vDelta = random.nextDouble() + 0.5;
private int height = 15;
private int width = 3;
private double x;
private double y = -height;
private Rectangle2D shape;
public Drop(Dimension size) {
x = random.nextInt(size.width - width) + width;
y = random.nextInt(size.height - height) + height;
shape = new Rectangle2D.Double(x, y, width, height);
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.BLUE);
g2d.fill(shape);
}
public void update(Dimension size) {
y += vDelta;
if (y > size.height) {
y = -height;
x = random.nextInt(size.width - width) + width;
}
shape.setRect(x, y, width, height);
}
}
}

how do i convert from private inner class to a runnable interface?

so im given a working code as below, but then i have to convert it to use runnable interface
package lab12;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class MultiThreaded2 extends JFrame implements ActionListener {
public static final int WIDTH = 600;
public static final int HEIGHT = 400;
public static final int FILL_WIDTH = 600;
public static final int FILL_HEIGHT = 400;
public static final int SQUARE_SIZE = 10;
public static final int PAUSE = 100; // milliseconds
private JPanel box;
public static void main(String[] args) {
MultiThreaded2 gui = new MultiThreaded2();
gui.setVisible(true);
}
public MultiThreaded2() {
setSize(WIDTH, HEIGHT);
setTitle("Threaded Fill Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
box = new JPanel();
add(box, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
JButton startButton = new JButton("Start");
startButton.addActionListener(this);
buttonPanel.add(startButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(this);
buttonPanel.add(stopButton);
add(buttonPanel, BorderLayout.SOUTH);
}
public void run() {
Graphics g = box.getGraphics();
int count = 0;
for (int y = 0; y < FILL_HEIGHT; y = y + SQUARE_SIZE) {
for (int x = 0; x < FILL_WIDTH; x = x + SQUARE_SIZE) {
if (count % 2 == 0) {
g.setColor(Color.red);
g.fillRect(x, y, SQUARE_SIZE, SQUARE_SIZE);
} else {
g.setColor(Color.blue);
g.drawRect(x, y, SQUARE_SIZE, SQUARE_SIZE);
}
try {
Thread.sleep(PAUSE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count++;
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Start")) {
SecondThread secondThread = new SecondThread();
secondThread.start();
} else if (e.getActionCommand().equals("Stop")) {
System.exit(0);
}
}
private class SecondThread extends Thread {
public void run() {
Graphics g = box.getGraphics();
int count = 0;
for (int y = 0; y < FILL_HEIGHT; y = y + SQUARE_SIZE) {
for (int x = 0; x < FILL_WIDTH; x = x + SQUARE_SIZE) {
if (count % 2 == 0) {
g.setColor(Color.red);
g.fillRect(x, y, SQUARE_SIZE, SQUARE_SIZE);
} else {
g.setColor(Color.blue);
g.drawRect(x, y, SQUARE_SIZE, SQUARE_SIZE);
}
try {
Thread.sleep(PAUSE);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count++;
}
}
}
}
}
i understand that i must do something tot he public class secondthread yeah? but i dont know how to convert it to runnable since everything is working already.
i tried deleting the "extends thread" and insert " implements runnable" but that just gives me error. adding both "extends thread" and "implements runnable" works but i doubt thats what i had to do
It's kind of hard for anybody to tell you what an error message means if you don't tell us what the error message said, but here's a guess:
If you do nothing else but change SecondThread extends Thread to SecondThread implements Runnable, then secondThread.start() isn't going to compile because your SecondThread class does not define a start() method.
So, given a ... implements Runnable object, how do you get a thread to run it?
I suggest you spend some time with the Java Concurrency tutorial. https://docs.oracle.com/javase/tutorial/essential/concurrency/
The answer to my question is right near the beginning.

using button click event to update variables in java

i have drawn a graph and placed a 20*20 pixel box in it and i am trying to move the box around with a bunch of buttons. the trouble is, i cant seem to change the X-axis and Y-axis values of the box from within the action listener. this is my first graphics application, help!
GrapMain.java
import java.awt.BorderLayout;
import javax.swing.JFrame;
import java.awt.Color;
import javax.swing.JTextField;
public class GraphMain {
public static void main(String [] args){
Display nashDisplay = new Display();
nashDisplay.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Graph.java
import java.awt.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Graph extends JPanel {
int x = 5, y = 100;
Graph (int x, int y){
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.WHITE);
//horizontal lines
g.setColor(Color.RED);
for (int height=20; height<200; height+=20){
g.drawLine(5, height, 480, height);
}
//verticle lines
g.setColor(Color.RED);
for (int height=5; height<400; height+=20){
g.drawLine(height,200,height,10);
}
//the box
g.setColor(Color.BLACK);
g.fillRect(this.x, this.y, 20, 20);
//g.fillRect((+20 to move right one box),(+20 to move down one box), 20, 20);
//g.fillRect((-20 to move left one box),(-20 to move up one box), 20, 20);
}
}
Display.java
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Display extends JFrame {
int X = 5, Y = 100;
private JButton left, right, up, down;
Graph dude = new Graph(X, Y);
public Display() {
super("nash's graph(moving the box!)");
JButton left = new JButton("move left");
add(left, BorderLayout.WEST);
left.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
X = X - 20;
}
});
JButton right = new JButton("move right");
add(right, BorderLayout.EAST);
right.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
X = X + 20;
}
});
JButton up = new JButton("move up");
add(up, BorderLayout.NORTH);
up.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
Y = Y - 20;
}
});
JButton down = new JButton("move down");
add(down, BorderLayout.SOUTH);
down.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
Y = Y + 20;
}
});
setSize(500, 300);
setVisible(true);
add(dude, BorderLayout.CENTER);
}
}
You need To repaint after you cange the x and y value Like this :
JButton left = new JButton("move left");
add(left, BorderLayout.WEST);
left.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
X = X - 20;
dude.x = X;
dude.y = Y;
repaint();
}
});
JButton right = new JButton("move right");
add(right, BorderLayout.EAST);
right.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
X = X + 20;
dude.x = X;
dude.y = Y;
repaint();
}
});
JButton up = new JButton("move up");
add(up, BorderLayout.NORTH);
up.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
Y = Y - 20;
dude.x = X;
dude.y = Y;
repaint();
}
});
JButton down = new JButton("move down");
add(down, BorderLayout.SOUTH);
down.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
Y = Y + 20;
dude.x = X;
dude.y = Y;
repaint();
}
});

Java: JSplitPane duplicates top panel's contents to bottom panel when Timer is active

So I have a JSplitPane, and two JPanels - one on top, one on the bottom. In both panels I overrode the paintComponent method and added my own graphics. In the bottom panel, I wanted to add an animation. When the panel does not repaint, it's fine, but as soon as the Timer (javax.swing.Timer) starts to call repaints, the bottom panel mimics the appearance of the top panel and glitches out. The actual animations are not refreshed, but rather it keeps on adding (like a dragged paintbrush instead of a moving object).
Here's the code for the Bottom Panel class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
import javax.swing.Timer;
public class WaitControls extends JPanel {
private int pos;
public WaitControls(){
setBackground(Color.gray);
pos = 0;
}
public void progress(){
//animation timer:
Timer timer = new Timer(30, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
pos++;
repaint();
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g){
g.fillRect(pos, pos, 10, 20);
}
}
And here's the code for the Splitpane class:
//my classes (imported packages)
import rcc.controls.ControlPanel;
import rcc.controls.InitControls;
import rcc.controls.WaitControls;
import rcc.video.Screen;
import javax.swing.JSplitPane;
public class MainPanel extends JSplitPane{
public RCC rcc;
public Screen screen;
private int height;
public ControlPanel curPanel;
public MainPanel(RCC rcc, Screen screen, int height){
super(JSplitPane.VERTICAL_SPLIT);
this.rcc = rcc;
this.screen = screen;
this.height = height;
setDividerSize(2);
setEnabled(false);
setTopComponent(screen);
setToInitControls();
}
//sets the control panel to init controls ***WORKS FINE***
public void setToInitControls(){
InitControls initCtrls = new InitControls(this);
setBottomComponent(initCtrls);
curPanel = initCtrls;
setDividerLocation(height / 4 * 3);
}
//sets the control panel to wait controls (trying to connect) ***GLITCHES***
public void setToWaitControls(){
WaitControls waitCtrls = new WaitControls();
setBottomComponent(waitCtrls);
curPanel = waitCtrls;
setDividerLocation(height / 4 * 3);
waitCtrls.progress();
}
}
The top panel is a bit complicated. It involves mouse action (including a MouseEntered listener) and animates to interact with user mouse input.
The strange thing is, I have another bottom panel that was swapped out that also uses animations, and a timer, and does not have this glitch.
Any ideas what may have caused this? Thank you for all your help!
I can't imagine how your animations works,
1/ but if animation(s) depends of by any of Listener then Timer must be Timer#restart();
2/ check (example), how to pass addNotify()/removeNotify() for start/stop animatiom(s)
NOTE required fullHD monitor for better output or change code line
for (int iPanels = 0; iPanels < 3; iPanels++) {
to
for (int iPanels = 0; iPanels < 2; iPanels++) {
Example:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class AnimationBackground {
public AnimationBackground() {
Random random = new Random();
JFrame frame = new JFrame("Animation Background");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLayout(new GridLayout(0, 3, 10, 10));
for (int iPanels = 0; iPanels < 3; iPanels++) {
final MyJPanel panel = new MyJPanel();
panel.setBackground(Color.BLACK);
for (int i = 0; i < 50; i++) {
Star star = new Star(new Point(random.nextInt(490), random.nextInt(490)));
star.setColor(new Color(100 + random.nextInt(155), 100 + random.nextInt(155), 100 + random.nextInt(155)));
star.setxIncr(-3 + random.nextInt(7));
star.setyIncr(-3 + random.nextInt(7));
panel.add(star);
}
panel.setLayout(new GridLayout(10, 1));
JLabel label = new JLabel("This is a Starry background.", JLabel.CENTER);
label.setForeground(Color.WHITE);
panel.add(label);
JPanel stopPanel = new JPanel();
stopPanel.setOpaque(false);
stopPanel.add(new JButton(new AbstractAction("Stop this madness!!") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
panel.stopAnimation();
}
}));
panel.add(stopPanel);
JPanel startPanel = new JPanel();
startPanel.setOpaque(false);
startPanel.add(new JButton(new AbstractAction("Start moving...") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
panel.startAnimation();
}
}));
panel.add(startPanel);
frame.add(panel);
}
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
AnimationBackground animationBackground = new AnimationBackground();
}
});
}
class Star extends Polygon {
private static final long serialVersionUID = 1L;
private Point location = null;
private Color color = Color.YELLOW;
private int xIncr, yIncr;
static final int WIDTH = 500, HEIGHT = 500;
Star(Point location) {
int x = location.x;
int y = location.y;
this.location = location;
this.addPoint(x, y + 8);
this.addPoint(x + 8, y + 8);
this.addPoint(x + 11, y);
this.addPoint(x + 14, y + 8);
this.addPoint(x + 22, y + 8);
this.addPoint(x + 17, y + 12);
this.addPoint(x + 21, y + 20);
this.addPoint(x + 11, y + 14);
this.addPoint(x + 3, y + 20);
this.addPoint(x + 6, y + 12);
}
public void setColor(Color color) {
this.color = color;
}
public void move() {
if (location.x < 0 || location.x > WIDTH) {
xIncr = -xIncr;
}
if (location.y < 0 || location.y > WIDTH) {
yIncr = -yIncr;
}
translate(xIncr, yIncr);
location.setLocation(location.x + xIncr, location.y + yIncr);
}
public void setxIncr(int xIncr) {
this.xIncr = xIncr;
}
public void setyIncr(int yIncr) {
this.yIncr = yIncr;
}
public Color getColor() {
return color;
}
}
class MyJPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ArrayList<Star> stars = new ArrayList<Star>();
private Timer timer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Star star : stars) {
star.move();
}
repaint();
}
});
public void stopAnimation() {
if (timer.isRunning()) {
timer.stop();
}
}
public void startAnimation() {
if (!timer.isRunning()) {
timer.start();
}
}
#Override
public void addNotify() {
super.addNotify();
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
timer.stop();
}
MyJPanel() {
this.setPreferredSize(new Dimension(520, 520));
}
public void add(Star star) {
stars.add(star);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Star star : stars) {
g.setColor(star.getColor());
g.fillPolygon(star);
}
}
}
}

Categories