how to fix paint component not invoking paintComponent? - java

I looked through some of the other questions similar to mine, but none of them seemed of help when i tried their fixes, How would i go about fixing this as its the only thing stopping my programme from printing rectangles which is vital.
Below is the code for the entire programme as im not sure in where the problem lies, only what the problem is. The stuff that is commented I'm currently not using, but I'm keeping it in there just in case I find a use for it later on. Many thanks
Currently, my programme does not draw any sort of rectangle as it should, and its because repaint doesn't invoke the paintcomponent. My question is basically asking as to why nothing is printed when I start it.
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* Write a description of class Game here.
*
* #author Adam Steele
* #version 1.0.0
*/
public class Game extends JPanel implements MouseListener
{
// logger
private static final Logger LOGGER = Logger.getLogger(Game.class.getName());
// variables
private boolean isGolden; // Class wide boolean for whether rectangle is golden
private int score; // Stores the score
private int noOfAttempts; // stores number of rectangles that are created
private int goldTimer; // attempts before fail & new rectangle is created
// graphics
private Rectangle box;
private JFrame frame;
private JPanel panel;
// testing
private ArrayList<Rect> rects = new ArrayList<Rect>();
/**
* Constructor for objects of class Game
*/
public Game()
{
setup();
}
public void setup()
{
LOGGER.info("setup has been called");
// initalise frame
frame = new JFrame();
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 600;
// set frame attributes
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Gold Picker");
// initalise panel
panel = new JPanel();
panel.addMouseListener(this);
// add things to panel - ie. score, time limit, etc.
// panel.add();
JLabel amLabel = new JLabel("I am a GUI label.");
panel.add(amLabel);
JButton button = new JButton("Button");
button.setBackground(Color.YELLOW);
button.setForeground(Color.GREEN);
panel.add(button);
// add panel to frame
frame.add(panel);
// Make frame visible
showFrame();
LOGGER.info("Game window has been created");
// (re)set variables
score = 0;
noOfAttempts = 0;
goldTimer = 30;
// this is to check variable initalisation
LOGGER.info("Variables have been initalised at: score = " + score + ", noOfAttempts = " + noOfAttempts + ", goldTimer = " + goldTimer);
// start game
decideGolden();
}
public void showFrame()
{
frame.setVisible(true);
}
/**
* A method that decides if the rectangle will be golden based on a random chance
*/
public void decideGolden()
{
double goldProportion = Math.random() * 1;
double goldChance = Math.random() * 1;
//System.out.println(goldChance + " " + goldProportion);
if(goldChance <= goldProportion) {
isGolden = true;
} else {
isGolden = false;
}
LOGGER.info("isGolden has been set to " + isGolden);
timedRect();
}
/**
* Method for generating rectangled on timed intervals
*/
public void timedRect()
{
/*
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run()
{
}
}, 20000, 20000 );
/*
if(isGolden) {
repaint();
} else {
createNormalRectangle();
}
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
}
},
20000); */
LOGGER.info("timedRect has been called");
for(int i = 0; i < goldTimer; i++) {
try {
LOGGER.info("try has been reached");
//repaint();
drawRectangle();
Thread.sleep(20000); // wait 20 seconds..
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
LOGGER.info("paintComponent has been called with " + g);
/*
int x = 400;
int y = 300;
// Using Math.random() or .nextInt() we could make random gold rects
int width = 100;
int height = 100;
LOGGER.info("x = " + x + ", y = " + y + ", width = " + width + ", height = " + height);
if(isGolden) {
//g.drawRect(x, y, width, height);
g.setColor(Color.BLACK);
g.fillRect(x, y, 100, 100); // g.fillRect(x, y, size, size);
} else {
//g.drawRect(x, y, width, height);
g.setColor(Color.BLACK);
g.fillRect(x, y, 100, 100);
}
*/
Graphics2D g2d = (Graphics2D) g;
for(Rect rectangle : rects) { // for each Rect object in rect ArrayList ..
rectangle.paint(g2d);
}
}
/**
*
*/
public void drawRectangle()
{
int x = (int) (Math.random() * getWidth());
int y = (int) (Math.random() * getHeight());
int width = (int) (Math.random() * (getWidth() / 4));
int height = (int) (Math.random() * (getHeight() / 4));
// LOGGER.info("x = " + x + ", y = " + y + ", width = " + width + ", height = " + height);
if (x + width > getWidth()) {
x = getWidth() - width;
}
if (y + height > getHeight()) {
y = getHeight() - height;
}
Color color = new Color(
(int) (Math.random() * 255),
(int) (Math.random() * 255),
(int) (Math.random() * 255));
rects.add(new Rect(x, y, width, height, color));
repaint();
// LOGGER.info("repaint has been called, check if paintComponent has been called..");
}
/**
* these methods are needed to override the MouseListener
* ..and hence needed to implement the MouseListener
* ..which will probably only be used for testing
* ..actionlistener maybe more appropriate
*/
#Override
public void mouseClicked(MouseEvent e) {
LOGGER.info("Mouse has been clicked");
drawRectangle();
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
}
Rect class in case its needed
Rect class
import java.awt.*;
/**
* Deaals with misc properties of rect
* Inherits the Rectangle class from java.awt.Rectangle
public class Rect extends Rectangle
{
private Color color;
/**
* Constructor for objects of class Rect
*/
public Rect(int x, int y, int width, int height, Color color)
{
super(x, y, width, height);
this.color = color;
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
g2d.fill(this);
}
}

Basically, you never actually add Game to anything which can display it, therefore it will never be painted.
Before a component can be painted, it must be added to a container which is realised on the screen.
One of the issues you're having is your Game class is taking on to much responsibility, it should be focused on displaying and managing the game state, not also creating the basic UI.
Another issue you're going to have is your timedRect method will block the EDT, preventing anything from getting painted anyway
This is a "basic" example (I've not tested it because I don't have your Rect class), but conceptually it should get you closer to your goal.
Realistically, I'd have a separate "main" class which started the app, setup the initial state, created the UI and gets the ball rolling.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.w3c.dom.css.Rect;
public class Game extends JPanel implements MouseListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
LOGGER.info("setup has been called");
// initalise frame
JFrame frame = new JFrame();
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 600;
// set frame attributes
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Gold Picker");
// initalise panel
JPanel panel = new Game();
// add things to panel - ie. score, time limit, etc.
// panel.add();
JLabel amLabel = new JLabel("I am a GUI label.");
panel.add(amLabel);
JButton button = new JButton("Button");
button.setBackground(Color.YELLOW);
button.setForeground(Color.GREEN);
panel.add(button);
// add panel to frame
frame.add(panel);
frame.setVisible(true);
LOGGER.info("Game window has been created");
}
});
}
// logger
private static final Logger LOGGER = Logger.getLogger(Game.class.getName());
// variables
private boolean isGolden; // Class wide boolean for whether rectangle is golden
private int score; // Stores the score
private int noOfAttempts; // stores number of rectangles that are created
private int goldTimer; // attempts before fail & new rectangle is created
private int gameLoops = 0;
// graphics
private Rectangle box;
// testing
private ArrayList<Rect> rects = new ArrayList<Rect>();
/**
* Constructor for objects of class Game
*/
public Game() {
addMouseListener(this);
// (re)set variables
score = 0;
noOfAttempts = 0;
goldTimer = 30;
// this is to check variable initalisation
LOGGER.info("Variables have been initalised at: score = " + score + ", noOfAttempts = " + noOfAttempts + ", goldTimer = " + goldTimer);
decideGolden();
}
/**
* A method that decides if the rectangle will be golden based on a random
* chance
*/
public void decideGolden() {
double goldProportion = Math.random() * 1;
double goldChance = Math.random() * 1;
//System.out.println(goldChance + " " + goldProportion);
if (goldChance <= goldProportion) {
isGolden = true;
} else {
isGolden = false;
}
LOGGER.info("isGolden has been set to " + isGolden);
timedRect();
}
/**
* Method for generating rectangled on timed intervals
*/
public void timedRect() {
Timer timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (gameLoops < goldTimer) {
LOGGER.info("try has been reached");
//repaint();
drawRectangle();
gameLoops++;
} else {
((Timer) (e.getSource())).stop();
}
}
});
timer.start();
LOGGER.info("timedRect has been called");
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
LOGGER.info("paintComponent has been called with " + g);
Graphics2D g2d = (Graphics2D) g;
for (Rect rectangle : rects) { // for each Rect object in rect ArrayList ..
rectangle.paint(g2d);
}
}
/**
*
*/
public void drawRectangle() {
int x = (int) (Math.random() * getWidth());
int y = (int) (Math.random() * getHeight());
int width = (int) (Math.random() * (getWidth() / 4));
int height = (int) (Math.random() * (getHeight() / 4));
// LOGGER.info("x = " + x + ", y = " + y + ", width = " + width + ", height = " + height);
if (x + width > getWidth()) {
x = getWidth() - width;
}
if (y + height > getHeight()) {
y = getHeight() - height;
}
Color color = new Color(
(int) (Math.random() * 255),
(int) (Math.random() * 255),
(int) (Math.random() * 255));
rects.add(new Rect(x, y, width, height, color));
repaint();
LOGGER.info("repaint has been called, check if paintComponent has been called..");
}
/**
* these methods are needed to override the MouseListener ..and hence needed
* to implement the MouseListener ..which will probably only be used for
* testing ..actionlistener maybe more appropriate
*/
#Override
public void mouseClicked(MouseEvent e) {
LOGGER.info("Mouse has been clicked");
drawRectangle();
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public class Rect extends Rectangle {
private Color color;
/**
* Constructor for objects of class Rect
*/
public Rect(int x, int y, int width, int height, Color color) {
super(x, y, width, height);
this.color = color;
}
public void paint(Graphics2D g2d) {
g2d.setColor(color);
g2d.fill(this);
}
}
}

Why are you extending JPanel when you have an instance of JPanel? When you extend a class, you inherit all of its functionality.
Instead of using your instance "panel.add" whatever, get rid of your JPanel instance and use this.add.
Which leads to my next statement:
Your class should extend JComponent, you're not overriding paintcomponent because JPanel doesn't have a paintcomponent() method to override.
Read up on how to properly implement JComponent and JFrame and how they go together. Normally you add all your drawings to the JComponent, then you say frame.add(component), where component is of type JComponent.
Try reimplementing your code in this fashion and seperate your classes, now you don't have to follow this exact format but from what you've posted, I think you're lost.
Implement a class that extends JFrame, this will be your frame.
Implement a class that "knows" how to draw your rectangle shapes. You must put it in a method called draw(Graphics2D g2){}.
Implement a class that extends JComponent, this class may have an arraylist of your "rectangle" objects.
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// initialize your rectangle objects here
for(Rectangles rects: whateveryourarraylistvariable) {
rects.draw(g2);
}
}
good luck

Related

Why does my method inside a class only draw the first circle but if i just use filloval method inside a for loop it displays all circles?

I'm writing a program that displays a circle every time you click the Jpanel. I have it all set up and I want to be able to use the drawCircle method I created in my circle class to draw the circles in the paintComponent method. I'm storing all of the circles created in a linked list. Then I interate through each Circle in the list and try to use the method in my Circle class called drawCircle().
For some reason, if I try to use c1.drawCircle() in a for loop in the My panel class it only draws the last circle that was created. But if I just use g.fillOval(with the correct parameters grabbing the values from the Circle class) in the for loop it works properly and displays all the circles. Why is it doing this and how do I go about using the method in the Circle class properly
I'm unsure what to try right now.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
public class MouseTest {
private int borderWidth = 20;
private JFrame frame;
private boolean tracking;
private boolean start;
private boolean clearBol;
private int xstart;
private int ystart;
private int xend;
private int yend;
private LinkedList<Circle> circles;
public MouseTest() {
tracking = false;
start = false;
circles = new LinkedList<Circle>();
frame = new JFrame();
frame.setBounds(250, 98, 600, 480);
frame.setTitle("Window number three");
Container cp = frame.getContentPane();
JButton clear = new JButton("Clear");
JToggleButton circleButton = new JToggleButton()("Circles");
JToggleButton drawButton = new JToggleButton("Draw");
ButtonGroup circleOrDraw = new ButtonGroup();
MyPanel pane = new MyPanel();
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
clearBol = true;
frame.repaint();
}
});
JPanel top = new JPanel();
top.setLayout(new FlowLayout());
top.add(clear);
circleOrDraw.add(circleButton);
circleOrDraw.add(drawButton);
top.add(circleOrDraw);
cp.add(top, BorderLayout.NORTH);
cp.add(pane, BorderLayout.CENTER);
pane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
xstart = e.getX();
ystart = e.getY();
start = false;
}
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
if (xend < xstart) {
int tmp = xstart;
xstart = xend;
xend = tmp;
}
if (yend < ystart) {
int tmp = ystart;
ystart = yend;
yend = tmp;
}
start = true;
frame.repaint();
}
});
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
if (tracking) {
int x = e.getX();
int y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
});
frame.setVisible(true);
} // constructor
public static void main(String[] arg) {
MouseTest first = new MouseTest();
} // main
public void msg(String s) {
System.out.println(s);
}
public void trackMouse() {
tracking = !tracking;
} // trackMouse
public class Circle extends JPanel {
Graphics g;
int x;
int y;
int r;
Color color;
public Circle(Graphics g, int x, int y, int r) {
this.g = g;
this.x = x;
this.y = y;
this.r = r;
int red = (int) (256 * Math.random());
int green = (int) (256 * Math.random());
int blue = (int) (256 * Math.random());
this.color = new Color(red, green, blue);
}
public void drawCircle() {
int x2 = x - (r / 2);
int y2 = y - (this.r / 2);
g.setColor(color);
g.fillOval(x2, y2, this.r, this.r);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public int getR() {
return r;
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
if (start) {
circles.add(new Circle(g, xend, yend,
(int) ((250 * Math.random() + 4))));
//Area where I'm having issues
for (Circle c1 : circles) {
msg("" + c1.getX());
// this method that I created in the circle class will only draw the first circle
//c1.drawCircle();
int r = c1.getR();
int x = c1.getX();
int y = c1.getY();
g.setColor(c1.getColor());
g.fillOval((c1.getX() - (r / 2)), (c1.getY() - (r / 2)),
r, r); // this will display all the circles
}
int size = circles.size();
msg(size + " Size");
msg("" + circles.getLast().getX());
}
if (clearBol) {
super.paintComponent(g);
circles.clear();
clearBol= false;
}
Thank you!
Most of the structure of your class needs to be changed
Your MyPanel should have a better name to give its functionality, maybe something like DrawingPanel.
The DrawingPanel is then responsible for managing the Circles to be painted. So typically you would just use an ArrayList to hold the Circle information.
Then you would add a method to the class, like addCircle(...) to add the Circle information to the ArrayList and then invoke repaint().
Then in your paintComponent(...) method the first thing you do is invoke super.paintComponent(...) to clear the panel. Then you iterate through the ArrayList and paint all the Circles. There will be no need for the Boolean values to check the state of the class. The ArrayList will either have circles or it won't.
You would also need a method like clearCircles(). This would simply remove all the Circles from the ArrayList and invoke repaint() on itself.
Your Circle class should NOT extend JPanel. It should just be a class that contains the information need to paint the circle: x/y location, size of circle and color of circle.
Now your frame is responsible of displaying your DrawingPanel and the buttons.
When you click the "Clear" button you simply invoke the clearCircles() method of the DrawingPanel.
For your MouseListener you simply invoke the addCircle(...) method of your DrawingPanel once you have all the information needed to create a Circle instance.
For a complete working example that incorporates all these suggestions check out the DrawOnComponent example found in Custom Painting Approaches

How do I make a sprite move in a custom JPanel?

How do I make a sprite move in a custom JPanel?
I have looked at the similar questions and although one question is similar, it isn't addressing my problem. I have a sprite in a JPanel and I am unable to get it to move. One of the requirements I have to meet for the program is that it must begin moving when a JButton is pressed (Mouse Click). I have the code set-up in a way I believe should work, but it will spit out a long list of errors when I press the button. I'm also required to have the panel be a custom panel class.
What I need to know is this:
Methods (ha) of programming sprite movement.
Continuing to move the sprite without a trail.
Making the sprite bounce off the edges of the panel. Done (Unable to test due to no moving ball)
Here's the code I have (MainClient).
package clientPackage;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import logicPack.Logic;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ClientClass
{
Ball mSolo = new Ball();
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientClass window = new ClientClass();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClientClass()
{
initialize();
}
/**
* Initialize the contents of the frame.
*/
Logic Logical;
Graphics g;
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 590, 520);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
SpriteField panel = new SpriteField();
panel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
/* int tX = e.getX();
Logical.MoveBallX();
int tY = e.getY();
Logical.MoveBallY();
panel.repaint();*/
Logical.MoveBallX();
Logical.MoveBallY();
panel.repaint();
}
});
panel.setForeground(Color.WHITE);
panel.setBackground(Color.GRAY);
panel.setBounds(64, 92, 434, 355);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
Graphics2D g2 = (Graphics2D)g;
mSolo.DrawSprite(g2 , Logical.MoveBallX(), Logical.MoveBallY());
}
});
btnStart.setBounds(64, 13, 174, 60);
frame.getContentPane().add(btnStart);
}
}
And here are my other Classes (Logic)
package logicPack;
import clientPackage.Ball;
public class Logic
{
Ball mSolo;
public int MoveBallX()
{
int NewX = mSolo.xPos + 50;
return NewX;
}
public int MoveBallY()
{
int NewY = mSolo.yPos + 50;
return NewY;
}
//Motion, force, friction and collision GO HERE ONLY
}
SpriteField
package clientPackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class SpriteField extends JPanel
{
Ball mSolo;
SpriteField()
{
mSolo = new Ball();
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
mSolo.DrawSprite(g2 , mSolo.xPos , mSolo.yPos);
}
}
Ball
package clientPackage;
import java.awt.Color;
import java.awt.Graphics2D;
public class Ball
{
Ball()
{
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2, int xPos, int yPos)
{
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2 , yPos - diameter / 2 , diameter , diameter);
}
}
If you do not understand my Java comments, you can just ignore them.
If you need more details to help me, let me know.
EDIT 1:
Andrew, the closest article I could find used arrow keys to move a sprite. The article was "Sprite not moving in JPanel". All the other articles I found either addressed JPanels without sprites, or animating a sprite. However, I need a JButton that is MouseClicked to simply start the movement, and the ball does not change shape or color. I believe I have the collision part working, but I'm unable to test it until the ball starts moving.
EDIT 2:
LuxxMiner, Thanks for the hints. I have refined my collision portion to be a little more accurate using the getHeight and getWidth methods.
EDIT 3:
MadProgrammer, Thanks...? The problem is not the painting of the ball, I cannot get the ball to move in the first place to repaint it. And the example uses arrow keys, not a mouse click or JButton.
First, take a look at Painting in AWT and Swing and Performing Custom Painting to understand how painting works in Swing.
Let's have a look at the code...
You have a Ball class, which has it's own properties, but then your DrawSprite method passes in values which override these properties?
public class Ball {
Ball() {
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2, int xPos, int yPos) {
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2, yPos - diameter / 2, diameter, diameter);
}
}
What's the point of that? The Ball should paint it's own current state. You should get rid of the additional parameters
public class Ball {
Ball() {
}
public int xPos = 25;
public int yPos = 25;
int diameter = 25;
public void DrawSprite(Graphics2D g2) {
g2.setColor(Color.BLACK);
g2.fillOval(xPos - diameter / 2, yPos - diameter / 2, diameter, diameter);
}
}
ClientClass, Logic and SpriteField all have their own Ball references, none of which is shared so if Logic where to update the state of it's Ball, neither ClientClass or SpriteField would actually see those changes.
In reality, only SpriteField needs an instance of Ball, as it's basically the "ball container", it has the information need to determine if the ball moves out of bounds and wants to know when the ball should be repainted, better to isolate the functionality/responsibility for the Ball to SpriteField at this time.
You also need a means to actually move the ball. While you could use other events, I'd be nice if the ball just moved itself, to this end, you can use a Swing Timer, which won't block the Event Dispatching Thread, but which notifies the registered ActionListener within the context of the EDT, making it safe to update the UI from within.
public class SpriteField extends JPanel {
private Ball mSolo;
private Timer timer;
private int xDelta, yDelta;
public SpriteField() {
mSolo = new Ball();
do {
xDelta = (int) ((Math.random() * 8) - 4);
} while (xDelta == 0);
do {
yDelta = (int) ((Math.random() * 8) - 4);
} while (yDelta == 0);
}
public void start() {
if (timer == null || !timer.isRunning()) {
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
mSolo.xPos += xDelta;
mSolo.yPos += yDelta;
if (mSolo.xPos - (mSolo.diameter / 2) < 0) {
mSolo.xPos = mSolo.diameter / 2;
xDelta *= -1;
} else if (mSolo.xPos + (mSolo.diameter / 2) > getWidth()) {
mSolo.xPos = getWidth() - (mSolo.diameter / 2);
xDelta *= -1;
}
if (mSolo.yPos - (mSolo.diameter / 2) < 0) {
mSolo.yPos = (mSolo.diameter / 2);
yDelta *= -1;
} else if (mSolo.yPos + (mSolo.diameter / 2) > getHeight()) {
mSolo.yPos = getHeight() - (mSolo.diameter / 2);
yDelta *= -1;
}
repaint();
}
});
timer.start();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
mSolo.DrawSprite(g2);
}
}
Now, all you need to do, is when the "Start" button is clicked, call the start method
public class ClientClass {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientClass window = new ClientClass();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClientClass() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
// Logic Logical;
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 590, 520);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SpriteField panel = new SpriteField();
panel.setForeground(Color.WHITE);
panel.setBackground(Color.GRAY);
frame.getContentPane().add(panel);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.start();
}
});
frame.getContentPane().add(btnStart, BorderLayout.SOUTH);
}
}

java awt Canvas getInstance undefined (newbie)

Trying the exercise in lesson2 of the Udacity course. Despite importing the classes (I'm at java.awt.* now, but I also tried java.awt.Color and java.awt.Canvas separately (also need Shape))..
package com.jul.udacity.lesson2;
public class TestRectangle {
public static void main(String[] args) {
// TODO Auto-generated method stub
Rectangle rect1 = new Rectangle(100.0, 100.0, 200.0, 100.0);
rect1.draw();
}
}
And the class is copied from there and java.awt import added. Any help will be great. Thanks!
package com.jul.udacity.lesson2;
//HIDE
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
//import java.awt.Color;
//import java.awt.Shape;
//import java.awt.Canvas;
import java.awt.*;
public class Rectangle implements Shape
{
private Color color = Color.BLACK;
private boolean filled = false;
private double x;
private double y;
private double width;
private double height;
/**
Constructs an empty rectangle.
*/
public Rectangle()
{
x = 0;
y = 0;
width = 0;
height = 0;
}
/**
Constructs a rectangle.
#param x the leftmost x-coordinate
#param y the topmost y-coordinate
#param width the width
#param height the height
*/
public Rectangle(double x, double y, double width, double height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
Gets the leftmost x-position of this rectangle.
#return the leftmost x-position
*/
public int getX()
{
return (int) Math.round(x);
}
/**
Gets the topmost y-position of this rectangle.
#return the topmost y-position
*/
public int getY()
{
return (int) Math.round(y);
}
/**
Gets the width of this rectangle.
#return the width
*/
public int getWidth()
{
return (int) Math.round(width);
}
/**
Gets the height of this rectangle.
#return the height
*/
public int getHeight()
{
return (int) Math.round(height);
}
/**
Moves this rectangle by a given amount.
#param dx the amount by which to move in x-direction
#param dy the amount by which to move in y-direction
*/
public void translate(double dx, double dy)
{
x += dx;
y += dy;
Canvas.getInstance().repaint();
}
/**
Resizes this rectangle both horizontally and vertically.
#param dw the amount by which to resize the width on each side
#param dw the amount by which to resize the height on each side
*/
public void grow(double dw, double dh)
{
width += 2 * dw;
height += 2 * dh;
x -= dw;
y -= dh;
Canvas.getInstance().repaint();
}
/**
Sets the color of this rectangle.
#param newColor the new color
*/
public void setColor(Color newColor)
{
color = newColor;
Canvas.getInstance().repaint();
}
/**
Draws this rectangle.
*/
public void draw()
{
filled = false;
Canvas.getInstance().show(this);
}
/**
Fills this rectangle.
*/
public void fill()
{
filled = true;
Canvas.getInstance().show(this);
}
public String toString()
{
return "Rectangle[x=" + getX() + ",y=" + getY() + ",width=" + getWidth() + ",height=" + getHeight() + "]";
}
public void paintShape(Graphics2D g2)
{
Rectangle2D.Double rect = new Rectangle2D.Double(getX(), getY(),
getWidth(), getHeight());
g2.setColor(new java.awt.Color((int) color.getRed(), (int) color.getGreen(), (int) color.getBlue()));
if (filled)
{
g2.fill(rect);
}
else
{
g2.draw(rect);
}
}
}
You might want to check the lesson directions carefully. java.awt.Canvas has no getInstance() method. You just use new to make a Canvas. So you either didn't read carefully and are using the wrong Canvas, or there's something else going on.
Also the show() methods are deprecated, so I'm leaning towards you are supposed to be using a different Canvas class.
Also, Swing is not thread safe. Read up on how to use Swing objects
markspace is correct: Canvas here is not the class from java.awt - the Udacity instructors are using their own class called Canvas. I suggest grabbing the lesson files and using those. Here's the Canvas class from that Intro To Java Course:
import java.awt.image.BufferedImage;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.RescaleOp;
import java.io.IOException;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Canvas
{
private static Canvas canvas = new Canvas();
private ArrayList<Shape> shapes = new ArrayList<Shape>();
private BufferedImage background;
private JFrame frame;
private CanvasComponent component;
private static final int MIN_SIZE = 100;
private static final int MARGIN = 10;
private static final int LOCATION_OFFSET = 120;
class CanvasComponent extends JComponent
{
public void paintComponent(Graphics g)
{
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(java.awt.Color.BLACK);
if (background != null)
{
g.drawImage(background, 0, 0, null);
}
for (Shape s : new ArrayList<Shape>(shapes))
{
Graphics2D g2 = (Graphics2D) g.create();
s.paintShape(g2);
g2.dispose();
}
}
public Dimension getPreferredSize()
{
int maxx = MIN_SIZE;
int maxy = MIN_SIZE;
if (background != null)
{
maxx = Math.max(maxx, background.getWidth());
maxy = Math.max(maxx, background.getHeight());
}
for (Shape s : shapes)
{
maxx = (int) Math.max(maxx, s.getX() + s.getWidth());
maxy = (int) Math.max(maxy, s.getY() + s.getHeight());
}
return new Dimension(maxx + MARGIN, maxy + MARGIN);
}
}
private Canvas()
{
component = new CanvasComponent();
if (System.getProperty("com.horstmann.codecheck") == null)
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(component);
frame.pack();
frame.setLocation(LOCATION_OFFSET, LOCATION_OFFSET);
frame.setVisible(true);
}
else
{
final String SAVEFILE ="canvas.png";
final Thread currentThread = Thread.currentThread();
Thread watcherThread = new Thread()
{
public void run()
{
try
{
final int DELAY = 10;
while (currentThread.getState() != Thread.State.TERMINATED)
{
Thread.sleep(DELAY);
}
saveToDisk(SAVEFILE);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
};
watcherThread.start();
}
}
public static Canvas getInstance()
{
return canvas;
}
public void show(Shape s)
{
if (!shapes.contains(s))
{
shapes.add(s);
}
repaint();
}
public void repaint()
{
if (frame == null) return;
Dimension dim = component.getPreferredSize();
if (dim.getWidth() > component.getWidth()
|| dim.getHeight() > component.getHeight())
{
frame.pack();
}
else
{
frame.repaint();
}
}
/**
* Pauses so that the user can see the picture before it is transformed.
*/
public void pause()
{
if (frame == null) return;
JOptionPane.showMessageDialog(frame, "Click Ok to continue");
}
/**
* Takes a snapshot of the screen, fades it, and sets it as the background.
*/
public static void snapshot()
{
Dimension dim = getInstance().component.getPreferredSize();
java.awt.Rectangle rect = new java.awt.Rectangle(0, 0, dim.width, dim.height);
BufferedImage image = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(java.awt.Color.WHITE);
g.fillRect(0, 0, rect.width, rect.height);
g.setColor(java.awt.Color.BLACK);
getInstance().component.paintComponent(g);
float factor = 0.8f;
float base = 255f * (1f - factor);
RescaleOp op = new RescaleOp(factor, base, null);
BufferedImage filteredImage
= new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
op.filter(image, filteredImage);
getInstance().background = filteredImage;
getInstance().component.repaint();
}
public void saveToDisk(String fileName)
{
Dimension dim = component.getPreferredSize();
java.awt.Rectangle rect = new java.awt.Rectangle(0, 0, dim.width, dim.height);
BufferedImage image = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(java.awt.Color.WHITE);
g.fill(rect);
g.setColor(java.awt.Color.BLACK);
component.paintComponent(g);
String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
try
{
ImageIO.write(image, extension, new File(fileName));
}
catch(IOException e)
{
System.err.println("Was unable to save the image to " + fileName);
}
g.dispose();
}
}

How to animate Rectangle in JPanel?

I want to learn some tricks about JAVA for my project.
I want to animate my Rectangle leftoright and righttoleft but I can't apply the same functions for ball animation.
In addition,how can I start my ball in different x-direction with a border of y-coordinate ?
Thanks a lot for your advices and helping.
My codes:
import javax.swing.Timer;
import java.util.ArrayList;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MultipleBall extends JApplet {
public MultipleBall() {
add(new BallControl());
}
class BallControl extends JPanel {
private BallPanel ballPanel = new BallPanel();
private JButton Suspend = new JButton("Suspend");
private JButton Resume = new JButton("Resume");
private JButton Add = new JButton("+1");
private JButton Subtract = new JButton("-1");
private JScrollBar Delay = new JScrollBar();
public BallControl() {
// Group buttons in a panel
JPanel panel = new JPanel();
panel.add(Suspend);
panel.add(Resume);
panel.add(Add);
panel.add(Subtract);
// Add ball and buttons to the panel
ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
Delay.setOrientation(JScrollBar.HORIZONTAL);
ballPanel.setDelay(Delay.getMaximum());
setLayout(new BorderLayout());
add(Delay, BorderLayout.NORTH);
add(ballPanel, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
// Register listeners
Suspend.addActionListener(new Listener());
Resume.addActionListener(new Listener());
Add.addActionListener(new Listener());
Subtract.addActionListener(new Listener());
Delay.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
ballPanel.setDelay(Delay.getMaximum() - e.getValue());
}
});
}
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Suspend)
ballPanel.suspend();
else if (e.getSource() == Resume)
ballPanel.resume();
else if (e.getSource() == Add)
ballPanel.add();
else if (e.getSource() == Subtract)
ballPanel.subtract();
}
}
}
class BallPanel extends JPanel {
private int delay = 30;
private ArrayList<Ball> list = new ArrayList<Ball>();
// Create a timer with the initial delay
protected Timer timer = new Timer(delay, new ActionListener() {
/** Handle the action event */
public void actionPerformed(ActionEvent e) {
repaint();
}
});
public BallPanel() {
timer.start();
}
public void add() {
list.add(new Ball());
}
public void subtract() {
if (list.size() > 0)
list.remove(list.size() - 1); // Remove the last ball
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(185, 279, 50, 15);
g.setColor(Color.RED);
g.fillRect(185, 279, 50, 15);
for (int i = 0; i < list.size(); i++) {
Ball ball = (Ball) list.get(i); // Get a ball
g.setColor(ball.color); // Set ball color
// Check boundaries
if (ball.x < 0 || ball.x > getWidth())
ball.dx = -ball.dx;
if (ball.y < 0 || ball.y > getHeight())
ball.dy = -ball.dy;
// Adjust ball position
ball.x += ball.dx;
// ball.y += ball.dy;
g.fillOval(ball.x - ball.radius, ball.y - ball.radius,
ball.radius * 2, ball.radius * 2);
}
}
public void suspend() {
timer.stop();
}
public void resume() {
timer.start();
}
public void setDelay(int delay) {
this.delay = delay;
timer.setDelay(delay);
}
}
class Ball {
int x = 20;
int y = 20; // Current ball position
int dx = 2; // Increment on ball's x-coordinate
int dy = 2; // Increment on ball's y-coordinate
int radius = 15; // Ball radius
Color color = new Color((int) (Math.random() * 256),
(int) (Math.random() * 256), (int) (Math.random() * 256));
}
/** Main method */
public static void main(String[] args) {
JFrame frame = new JFrame();
JApplet applet = new MultipleBallApp();
frame.add(applet);
frame.setTitle("MultipleBallApp");
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null); // Center the frame
frame.setVisible(true);
}
}
can't apply the same functions for ball animation
This is probably your first mistake. In fact, this is exactly what you should be trying to do. The idea is, you should be trying to devise a means by what is painted/animated is abstract so it doesn't matter what the shape is you want to paint, you can apply it to the sam basic animation process...
For example, you could start with some kind interface which describes the basic properties of an animated entity...
public interface AnimatedShape {
public void update(Rectangle bounds);
public void paint(JComponent parent, Graphics2D g2d);
}
This says that an animated entity can be updated (moved) and painted. By convention (and because I'm lazy), I like to create an abstract implementation which implements the most common aspects...
public abstract class AbstractAnimatedShape implements AnimatedShape {
private Rectangle bounds;
private int dx, dy;
public AbstractAnimatedShape() {
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Rectangle getBounds() {
return bounds;
}
public int getDx() {
return dx;
}
public int getDy() {
return dy;
}
public void setDx(int dx) {
this.dx = dx;
}
public void setDy(int dy) {
this.dy = dy;
}
#Override
public void update(Rectangle parentBounds) {
Rectangle bounds = getBounds();
int dx = getDx();
int dy = getDy();
bounds.x += dx;
bounds.y += dy;
if (bounds.x < parentBounds.x) {
bounds.x = parentBounds.x;
setDx(dx *= -1);
} else if (bounds.x + bounds.width > parentBounds.x + parentBounds.width) {
bounds.x = parentBounds.x + (parentBounds.width - bounds.width);
setDx(dx *= -1);
}
if (bounds.y < parentBounds.y) {
bounds.y = parentBounds.y;
setDy(dy *= -1);
} else if (bounds.y + bounds.height > parentBounds.y + parentBounds.height) {
bounds.y = parentBounds.y + (parentBounds.height - bounds.height);
setDy(dy *= -1);
}
}
}
And then start creating implementations...
public class AnimatedBall extends AbstractAnimatedShape {
private Color color;
public AnimatedBall(int x, int y, int radius, Color color) {
setBounds(new Rectangle(x, y, radius * 2, radius * 2));
this.color = color;
setDx(Math.random() > 0.5 ? 2 : -2);
setDy(Math.random() > 0.5 ? 2 : -2);
}
public Color getColor() {
return color;
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(getColor());
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
In this manner, you can customise the way that the entity is animated and painted, but the basic logic for each instance of the entity is the same...
But what's all the point of this...
Basically, what it allows us to do is produce a "virtual" concept of all the animated objects and simplify there management, for example...
Instead of using a "tightly" coupled List, we can use a loosely couple List instead...
private ArrayList<AnimatedShape> list = new ArrayList<AnimatedShape>();
Then when we want the entities to be updated, we simply need to iterate the List and ask the entities to update...
protected Timer timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (AnimatedShape ball : list) {
ball.update(getBounds());
}
repaint();
}
});
And when they need to be painted...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (AnimatedShape ball : list) {
ball.paint(this, g2d);
}
}
Because the BallPane doesn't care what actually type of entity it is, but only that it's a type of AnimatedShape...makes life easier...
Now, my implementation of the AnimatedBall already randomise the direction of each instance of the ball, but you can also randomise the starting position when the ball is added using something like...
public void add() {
int radius = 15;
// Randomised position
int x = (int)(Math.random() * (getWidth() - (radius * 2))) + radius;
int y = (int)(Math.random() * (getHeight() - (radius * 2))) + radius;
Color color = new Color((int) (Math.random() * 256),
(int) (Math.random() * 256), (int) (Math.random() * 256));
AnimatedBall ball = new AnimatedBall(x, y, radius, color);
list.add(ball);
}
But how does this help you with adding a rectangle?
You now need to create an AnimatedRectangle that extends from AbstractAnimatedShape and implemented the required methods and add instances of this to the List of AnimatedShapes in the BallPane.
If you don't want the rectangle to be managed within the same list, you could create another list and manage it sepearatly (it create two additional methods, update(List<AnimatedShape>) and paint(List<AnimatedShape>, Graphics2D) passing in each individual list so as to reduce the duplicate code, but that's me)...
You can restrict the rectangles vertical movement by overriding the setDy method and ignoring any changes, for example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MultipleBall {
public MultipleBall() {
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("MultipleBallApp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new BallControl());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class BallControl extends JPanel {
private BallPanel ballPanel = new BallPanel();
private JButton Suspend = new JButton("Suspend");
private JButton Resume = new JButton("Resume");
private JButton Add = new JButton("+1");
private JButton Subtract = new JButton("-1");
private JScrollBar Delay = new JScrollBar();
public BallControl() {
// Group buttons in a panel
JPanel panel = new JPanel();
panel.add(Suspend);
panel.add(Resume);
panel.add(Add);
panel.add(Subtract);
// Add ball and buttons to the panel
ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
Delay.setOrientation(JScrollBar.HORIZONTAL);
ballPanel.setDelay(Delay.getMaximum());
setLayout(new BorderLayout());
add(Delay, BorderLayout.NORTH);
add(ballPanel, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
// Register listeners
Suspend.addActionListener(new Listener());
Resume.addActionListener(new Listener());
Add.addActionListener(new Listener());
Subtract.addActionListener(new Listener());
Delay.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
ballPanel.setDelay(Delay.getMaximum() - e.getValue());
}
});
}
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Suspend) {
ballPanel.suspend();
} else if (e.getSource() == Resume) {
ballPanel.resume();
} else if (e.getSource() == Add) {
ballPanel.add();
} else if (e.getSource() == Subtract) {
ballPanel.subtract();
}
}
}
}
class BallPanel extends JPanel {
private int delay = 30;
private ArrayList<AnimatedShape> list = new ArrayList<AnimatedShape>();
private AnimatedRectange rectangle;
public BallPanel() {
this.rectangle = new AnimatedRectange(-25, 200, 50, 25, Color.RED);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
// Create a timer with the initial delay
protected Timer timer = new Timer(delay, new ActionListener() {
/**
* Handle the action event
*/
#Override
public void actionPerformed(ActionEvent e) {
for (AnimatedShape ball : list) {
ball.update(getBounds());
}
rectangle.update(getBounds());
repaint();
}
});
public void add() {
int radius = 15;
// Randomised position
int x = (int) (Math.random() * (getWidth() - (radius * 2))) + radius;
int y = (int) (Math.random() * (getHeight() - (radius * 2))) + radius;
Color color = new Color((int) (Math.random() * 256),
(int) (Math.random() * 256), (int) (Math.random() * 256));
AnimatedBall ball = new AnimatedBall(x, y, radius, color);
list.add(ball);
}
public void subtract() {
if (list.size() > 0) {
list.remove(list.size() - 1); // Remove the last ball
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (AnimatedShape ball : list) {
ball.paint(this, g2d);
}
rectangle.paint(this, g2d);
}
public void suspend() {
timer.stop();
}
public void resume() {
timer.start();
}
public void setDelay(int delay) {
this.delay = delay;
timer.setDelay(delay);
}
}
public interface AnimatedShape {
public void update(Rectangle bounds);
public void paint(JComponent parent, Graphics2D g2d);
}
public abstract class AbstractAnimatedShape implements AnimatedShape {
private Rectangle bounds;
private int dx, dy;
public AbstractAnimatedShape() {
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Rectangle getBounds() {
return bounds;
}
public int getDx() {
return dx;
}
public int getDy() {
return dy;
}
public void setDx(int dx) {
this.dx = dx;
}
public void setDy(int dy) {
this.dy = dy;
}
#Override
public void update(Rectangle parentBounds) {
Rectangle bounds = getBounds();
int dx = getDx();
int dy = getDy();
bounds.x += dx;
bounds.y += dy;
if (bounds.x < parentBounds.x) {
bounds.x = parentBounds.x;
setDx(dx *= -1);
} else if (bounds.x + bounds.width > parentBounds.x + parentBounds.width) {
bounds.x = parentBounds.x + (parentBounds.width - bounds.width);
setDx(dx *= -1);
}
if (bounds.y < parentBounds.y) {
bounds.y = parentBounds.y;
setDy(dy *= -1);
} else if (bounds.y + bounds.height > parentBounds.y + parentBounds.height) {
bounds.y = parentBounds.y + (parentBounds.height - bounds.height);
setDy(dy *= -1);
}
}
}
public class AnimatedBall extends AbstractAnimatedShape {
private Color color;
public AnimatedBall(int x, int y, int radius, Color color) {
setBounds(new Rectangle(x, y, radius * 2, radius * 2));
this.color = color;
setDx(Math.random() > 0.5 ? 2 : -2);
setDy(Math.random() > 0.5 ? 2 : -2);
}
public Color getColor() {
return color;
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(getColor());
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
public class AnimatedRectange extends AbstractAnimatedShape {
private Color color;
public AnimatedRectange(int x, int y, int width, int height, Color color) {
setBounds(new Rectangle(x, y, width, height));
this.color = color;
setDx(2);
}
// Don't want to adjust the vertical speed
#Override
public void setDy(int dy) {
}
#Override
public void paint(JComponent parent, Graphics2D g2d) {
Rectangle bounds = getBounds();
g2d.setColor(color);
g2d.fill(bounds);
}
}
/**
* Main method
*/
public static void main(String[] args) {
new MultipleBall();
}
}
Amendment
You really should avoid adding JApplet to a JFrame, an applet has a prescribed life cycle and management process which you are ignoring. Better to focus on just using the BallControl panel as the core UI element and then add this to what ever top level container you want
You may find a JSlider more piratical then a JScrollBar, not to mention, it will look better on different platforms, most uses understand what a slider is used for...
Add a static variable like ballCount and add 1 to it every time you make a ball. In the Ball class, change the definition of y to something likey = 20 + ballcount*(radius*2+distanceInBalls)
public class RandomTests extends JApplet {
public RandomTests() {
add(new BallControl());
}
static int ballCount = 0;
class BallControl extends JPanel {
private BallPanel ballPanel = new BallPanel();
private JButton Suspend = new JButton("Suspend");
private JButton Resume = new JButton("Resume");
private JButton Add = new JButton("+1");
private JButton Subtract = new JButton("-1");
private JScrollBar Delay = new JScrollBar();
public BallControl() {
// Group buttons in a panel
JPanel panel = new JPanel();
panel.add(Suspend);
panel.add(Resume);
panel.add(Add);
panel.add(Subtract);
// Add ball and buttons to the panel
ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
Delay.setOrientation(JScrollBar.HORIZONTAL);
ballPanel.setDelay(Delay.getMaximum());
setLayout(new BorderLayout());
add(Delay, BorderLayout.NORTH);
add(ballPanel, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
// Register listeners
Suspend.addActionListener(new Listener());
Resume.addActionListener(new Listener());
Add.addActionListener(new Listener());
Subtract.addActionListener(new Listener());
Delay.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
ballPanel.setDelay(Delay.getMaximum() - e.getValue());
}
});
}
class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Suspend) ballPanel.suspend();
else if (e.getSource() == Resume) ballPanel.resume();
else if (e.getSource() == Add) ballPanel.add();
else if (e.getSource() == Subtract) ballPanel.subtract();
}
}
}
class BallPanel extends JPanel {
private int delay = 30;
private ArrayList<Ball> list = new ArrayList<Ball>();
// Create a timer with the initial delay
protected Timer timer = new Timer(delay, new ActionListener() {
/** Handle the action event */
public void actionPerformed(ActionEvent e) {
repaint();
}
});
public BallPanel() {
timer.start();
}
public void add() {
list.add(new Ball());
ballCount++;
}
public void subtract() {
if (list.size() > 0) list.remove(list.size() - 1); // Remove the last ball
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(185, 279, 50, 15);
g.setColor(Color.RED);
g.fillRect(185, 279, 50, 15);
for (int i = 0; i < list.size(); i++) {
Ball ball = (Ball) list.get(i); // Get a ball
g.setColor(ball.color); // Set ball color
// Check boundaries
if (ball.x < 0 || ball.x > getWidth()) ball.dx = -ball.dx;
if (ball.y < 0 || ball.y > getHeight()) ball.dy = -ball.dy;
// Adjust ball position
ball.x += ball.dx;
// ball.y += ball.dy;
g.fillOval(ball.x - ball.radius, ball.y - ball.radius, ball.radius * 2, ball.radius * 2);
}
}
public void suspend() {
timer.stop();
}
public void resume() {
timer.start();
}
public void setDelay(int delay) {
this.delay = delay;
timer.setDelay(delay);
}
}
class Ball {
int radius = 15; // Ball radius
int x = radius;
int y = 20 + (radius * ballCount * 2 + 15); // Current ball position
int dx = 2; // Increment on ball's x-coordinate
int dy = 2; // Increment on ball's y-coordinate
Color color = new Color((int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256));
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JApplet applet = new RandomTests();
frame.add(applet);
frame.setTitle("MultipleBallApp");
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null); // Center the frame
frame.setVisible(true);
}
}

How to create a cube in swing?

I am trying to make a class that when invoked by a JPanel, creates a cube. What I have seen though, is something called a ColorCube, which requires a "Universe" of some sort, and a Canvas, though I didn't find this method to be compatible with JPanel.
TO clarify, I am not asking how to create a custom JComponent(exactly), nor am I asking how to add color or rotate it, just how to create a class that when invoked by a JPanel renders a cube to the screen.
All you really need are x, y, and size passed to the Cube class, then
Take those arguments and build an array of corners points for a first square and also corner points for a second shifted square. See methods getCubeOnePoints and getCubeTwoPoints methods in the Cube class.
Draw the first square. Draw the second square, and connect the points from the point arrays. See the drawCube method in the Cube class.
Create an instance of the Cube class passing necessary arguments, and draw the cube. See CubePanel constructor and paintComponent method
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CubePanel extends JPanel{
private static final int D_W = 400;
private static final int D_H = 400;
Cube cube;
public CubePanel() {
cube = new Cube(75, 75, 200, 50);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
cube.drawCube(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
public class Cube {
int x, y, size, shift;
Point[] cubeOnePoints;
Point[] cubeTwoPoints;
public Cube(int x, int y, int size, int shift) {
this.x = x;
this.y = y;
this.size = size;
this.shift = shift;
cubeOnePoints = getCubeOnePoints();
cubeTwoPoints = getCubeTwoPoints();
}
private Point[] getCubeOnePoints() {
Point[] points = new Point[4];
points[0] = new Point(x, y);
points[1] = new Point(x + size, y);
points[2] = new Point(x + size, y + size);
points[3] = new Point(x, y + size);
return points;
}
private Point[] getCubeTwoPoints() {
int newX = x + shift;
int newY = y + shift;
Point[] points = new Point[4];
points[0] = new Point(newX, newY);
points[1] = new Point(newX + size, newY);
points[2] = new Point(newX + size, newY + size);
points[3] = new Point(newX, newY + size);
return points;
}
public void drawCube(Graphics g) {
g.drawRect(x, y, size, size);
g.drawRect(x + shift, y + shift, size, size);
// draw connecting lines
for (int i = 0; i < 4; i++) {
g.drawLine(cubeOnePoints[i].x, cubeOnePoints[i].y,
cubeTwoPoints[i].x, cubeTwoPoints[i].y);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new CubePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
UPDATE
"what if i wanted this in a 3d where the cube could be walked around "
Just create methods to shift all the xs or ys and call it, then repaint. The method could look something like
public void shiftLeft() {
x -= SHIFT_INC;
for (Point p : cubeOnePoints) {
p.x -= SHIFT_INC;
}
for (Point p : cubeTwoPoints) {
p.x -= SHIFT_INC;
}
}
In the example below, I just call it in a key bind with the ←key.
im.put(KeyStroke.getKeyStroke("LEFT"), "shiftLeft");
getActionMap().put("shiftLeft", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
cube.shiftLeft();
repaint();
}
});
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class CubePanel extends JPanel{
private static final int D_W = 400;
private static final int D_H = 300;
Cube cube;
public CubePanel() {
cube = new Cube(75, 75, 50, 15);
InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("RIGHT"), "shiftRight");
getActionMap().put("shiftRight", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
cube.shiftRight();
repaint();
}
});
im.put(KeyStroke.getKeyStroke("LEFT"), "shiftLeft");
getActionMap().put("shiftLeft", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
cube.shiftLeft();
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
cube.drawCube(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
public class Cube {
private static final int SHIFT_INC = 5;
int x, y, size, shift;
Point[] cubeOnePoints;
Point[] cubeTwoPoints;
public Cube(int x, int y, int size, int shift) {
this.x = x;
this.y = y;
this.size = size;
this.shift = shift;
cubeOnePoints = getCubeOnePoints();
cubeTwoPoints = getCubeTwoPoints();
}
private Point[] getCubeOnePoints() {
Point[] points = new Point[4];
points[0] = new Point(x, y);
points[1] = new Point(x + size, y);
points[2] = new Point(x + size, y + size);
points[3] = new Point(x, y + size);
return points;
}
private Point[] getCubeTwoPoints() {
int newX = x + shift;
int newY = y + shift;
Point[] points = new Point[4];
points[0] = new Point(newX, newY);
points[1] = new Point(newX + size, newY);
points[2] = new Point(newX + size, newY + size);
points[3] = new Point(newX, newY + size);
return points;
}
public void shiftLeft() {
x -= SHIFT_INC;
for (Point p : cubeOnePoints) {
p.x -= SHIFT_INC;
}
for (Point p : cubeTwoPoints) {
p.x -= SHIFT_INC;
}
}
public void shiftRight() {
x += SHIFT_INC;
for (Point p : cubeOnePoints) {
p.x += SHIFT_INC;
}
for (Point p : cubeTwoPoints) {
p.x += SHIFT_INC;
}
}
public void drawCube(Graphics g) {
g.drawRect(x, y, size, size);
g.drawRect(x + shift, y + shift, size, size);
// draw connecting lines
for (int i = 0; i < 4; i++) {
g.drawLine(cubeOnePoints[i].x, cubeOnePoints[i].y,
cubeTwoPoints[i].x, cubeTwoPoints[i].y);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new CubePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
package Box;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ComponentListener;
import java.awt.event.ComponentEvent;
public class Box2 extends JPanel
{
public Box2()
{
this.addComponentListener(new ComponentListener(){
public void componentShown(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
public void componentResized(ComponentEvent arg0) {
paintComponent(getGraphics());
}
public void componentMoved(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
public void componentHidden(ComponentEvent arg0) {
// TODO Auto-generated method stub
}
});
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.white);
Dimension d;
d=getSize();
int height, width;
height =d.height;
width=d.width;
int w,h;
javax.swing.border.Border linebor =BorderFactory.createLineBorder(new Color(0xAD85FF),6 );
g.drawRect(0,0, w=width/2, h=height/2);
g.drawRect(w/2,h/2,w/2*2,h/2*2);
g.drawLine(0,0,w/2,h/2);
g.drawLine(w,h,w/2+w/2*2,h/2+h/2*2);
g.drawLine(w,0,w/2+w/2*2,h/2);
g.drawLine(0,h,w/2,h/2+h/2*2);
//g.drawLine(0, height – borderControl, width, height – borderControl);
}
}
Now make another class for Main File
package Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Box2_main extends JPanel
{
public static void main(String[] args)
{
Box2 cube = new Box2();
JFrame frame = new JFrame("Cube2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(cube);
frame.setSize(500, 500);
frame.setVisible(true);
}
}
If you change the dimensions of the window then the size of the cube will also increase/decrease.

Categories

Resources