JPanel creates twice - java

I am trying to make a GUI for a battleship game. One class is for creating the GUI itself and a second class is on top of it to manage the board in the game. My problem is that the JPanel creates twice once a mouse click happens (the mouse click is supposed to be where one is firing in the game and then marks that as a hit/miss). I'm not sure why it is creating twice. Is it because of the passing of a panel? Code below and a photo of what the code generates.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BattleshipApplet extends JApplet implements MouseListener {
private final JButton playButton = new JButton("Play");
private final JLabel msgBar = new JLabel("Click Play to start game");
private BoardPanel panel;
public BattleshipApplet(){
playButton.addActionListener(this::playButtonClicked);
addMouseListener(this);
}
public void init(){
configureGui();
}
private void configureGui(){
setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttons.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
buttons.add(playButton);
add(buttons, BorderLayout.NORTH);
msgBar.setBorder(BorderFactory.createEmptyBorder(10,10,5,5));
add(createBoardPanel(), BorderLayout.CENTER);
add(msgBar, BorderLayout.SOUTH);
}
private BoardPanel createBoardPanel(){
panel = new BoardPanel();
return panel;
}
private void displayMessage(String msg){
msgBar.setText(msg);
}
private void playButtonClicked(ActionEvent event){
displayMessage("Play button clicked!");
}
public void mouseClicked(MouseEvent e) {
panel.mouseClickedAt(e.getX(), e.getY());
e.consume();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
}
The board class using JPanel
[![import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class BoardPanel extends JPanel {
int mx, my;
boolean rect1Clicked;
//gamePlay a;
public void init(){
rect1Clicked = false;
}
/***Your applet shall show the status of the board before and after
each shot, including the number of shots made and the status of
each place (no shot or hit/miss shot). ***/
public void paint(Graphics g){
boolean miss = false;
for (int i=0; i<11; i++){
g.setColor(Color.blue);
g.drawLine(20,20+i*28, 300, 20+i*28);
}
for (int i=0; i<11; i++)
g.drawLine(20+i*28,20,20+i*28,300);
//if inside board
if(rect1Clicked == true){
g.setColor(Color.green);
//aligns to square to check in computer board for hit/miss
int bx =(my-20)/28;
int by =(mx-20)/28;
//check hit on board
//if shot was a miss
if(miss == true ){
//update to white
g.setColor(Color.white);
}
//if shot was a hit
if(miss == false){
//update to red
g.setColor(Color.red);
}
//compare to line for fill
int fillx = mx/2;
int filly = my/2 ;
if(mx<=47){
fillx = 20;
}
if(mx>47 && mx<=75){
fillx = 48;
}
if(mx>75 && mx<=103){
fillx = 76;
}
if(mx>103 && mx <=131){
fillx = 104;
}
if(mx>131 && mx<=159){
fillx = 132;
}
if(mx>159 && mx<=187){
fillx = 160;
}
if(mx>187 && mx <=215){
fillx = 188;
}
if(mx>215 && mx <=243){
fillx = 216;
}
if(mx>243 && mx <=271){
fillx = 244;
}
if(mx>271 && mx<=299){
fillx = 272;
}
if(mx>299){
fillx = 300;
}
//y comparisons
if(my<=47){
filly = 20;
}
if(my>47 && my<=75){
filly = 48;
}
if(my>75 && my<=103){
filly = 76;
}
if(my>103 && my <=131){
filly = 104;
}
if(my>131 && my<=159){
filly = 132;
}
if(my>159 && my<=187){
filly = 160;
}
if(my>187 && my <=215){
filly = 188;
}
if(my>215 && my <=243){
filly = 216;
}
if(my>243 && my <=271){
filly = 244;
}
if(my>271 && my<=299){
filly = 272;
}
if(my>299){
filly = 300;
}
g.drawString("("+mx+","+my+")",mx,my);
//25 describes size of square
g.fillOval(fillx, filly, 25, 25);
}
}
public void game(BoardPanel p){
//while game plays
}
public void mouseClickedAt(int x, int y){
mx = x;
my = y;
//user clicked inside of board space
if(mx>20 && mx<300 && my>20 && my<300){
//send to board in MainBattleship
rect1Clicked = true;
}
//updates board
repaint();
}
}][1]][1]
I am so lost, thank you for any help!

Suggestions:
Don't override a JPanel's paint method but rather its paintComponent method as this is safer, and later when you want to do animation, will result in smoother animation.
Most important you almost always need to call the super's painting method within your own, else the JPanel will not remove previous image artifacts that need to be cleaned up. So if you continue to override paint (although I recommend against, this) the first line of your override should be super.paint(g);, or if you override paintComponent then the first line should be super.paintComponent(g);, of course assuming that you're methods use a Graphics parameter named g.
Also, add the MouseListener to the JPanel, not to the applet, since it is the mouse click location on the panel that matters to you.
Also, use a grid of components or some math to greatly simplify your code -- that ugly list of if blocks should be replaced by a much simpler for loop, one using basic math.
Consider extracting that logic discussed in the point above out of your painting method and into a model of some kind, perhaps a 2D array of boolean.
You're using a lot of "magic" numbers in your code, numbers that should be changed to a combination of constants and mathematically derived numbers.
Notice what happens if you click on your GUI, and then resize it, or if you minimize and then restore it -- you lose all red circles except for the last one pressed. This is another reason to use a grid of boolean or other model to hold state of the game, and then use this model when drawing your GUI.
On further thinking, you might want a 2D array of an enum or an int array, since the grid cell state will likely be more than 2 values (true or false), but rather will be three values -- untested, hit, and miss, and you'll likely want to fill your oval with red if a hit or white if a miss.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.*;
public class GridExample {
private static void createAndShowGui() {
final GridPanel gridPanel = new GridPanel();
JButton resetBtn = new JButton(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
gridPanel.reset();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(resetBtn);
JFrame frame = new JFrame("GridExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gridPanel);
frame.getContentPane().add(btnPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class GridPanel extends JPanel {
private static final int ROWS = 10;
private static final int CELL_WIDTH = 28;
private static final int PAD = 20;
private static final int PREF_W = ROWS * CELL_WIDTH + 2 * PAD;
private static final int PREF_H = PREF_W;
private static final Color GRID_COLOR = Color.blue;
private static final Color CIRCLE_COLOR = Color.red;
private static final int SML_GAP = 2;
private boolean[][] grid = new boolean[ROWS][ROWS];
public GridPanel() {
addMouseListener(new MyMouse());
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void reset() {
grid = new boolean[ROWS][ROWS]; // fills grid with false
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// draw grid:
g2.setColor(GRID_COLOR);
for (int i = 0; i <= ROWS; i++) {
int x1 = PAD + i * CELL_WIDTH;
int y1 = PAD;
int x2 = x1;
int y2 = PAD + CELL_WIDTH * ROWS;
g2.drawLine(x1, y1, x2, y2);
g2.drawLine(y1, x1, y2, x2);
}
// iterate through the grid boolean array
// draw red circles if the grid value is true.
g2.setColor(CIRCLE_COLOR);
int w = CELL_WIDTH - 2 * SML_GAP; // width of the circle to draw
int h = w;
// nested for loop to go through the grid array
for (int r = 0; r < grid.length; r++) {
for (int c = 0; c < grid[r].length; c++) {
if (grid[r][c]) {
int x = PAD + c * CELL_WIDTH + SML_GAP;
int y = PAD + r * CELL_WIDTH + SML_GAP;
g2.fillOval(x, y, w, h);
}
}
}
}
private class MyMouse extends MouseAdapter {
public void mousePressed(MouseEvent e) {
int x = e.getPoint().x;
int y = e.getPoint().y;
if (x < PAD || y < PAD) {
// clicked above or to right of grid
return;
}
int r = (y - PAD) / CELL_WIDTH;
int c = (x - PAD) / CELL_WIDTH;
// if clicked to right or below grid.
// the < 0 part is likely unnecessary, but why not be extra safe?
if (r >= ROWS || c >= ROWS || r < 0 || c < 0) {
return;
}
grid[r][c] = true;
repaint();
}
}
}

Related

Making a character land on a platform

Im trying to code a simple 2D game. I have a Square that you can move with a/w/d. I got jumping working with a sort of gravity but now I cant get myself to land on a platform. I know how to detect collision between two things but even still idk what to do. My gravity always pulls me down until I reach groundLevel which is part of the problem. Here is my code so far. There's a lot of experimenting happing so its pretty messy.
import javax.swing.Timer;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
/**
* Custom Graphics Example: Using key/button to move a line left or right.
*/
public class PlatformingGame extends JFrame implements ActionListener, KeyListener{
// Name-constants for the various dimensions
public static final int CANVAS_WIDTH = 800;
public static final int CANVAS_HEIGHT = 400;
public static final Color LINE_COLOR = Color.BLACK;
public static final Color CANVAS_BACKGROUND = Color.WHITE;
public int GRAVITY = 10;
public int TERMINAL_VELOCITY = 300;
public int vertical_speed = 0;
public int jumpSpeed;
public int groundLevel = CANVAS_HEIGHT;
int Shapes;
private DrawCanvas canvas; // the custom drawing canvas (extends JPanel)
public enum STATE {
PLAYING,
PAUSED,
ONGROUND,
INAIR
};
JButton btnStartRestat, btnExit;
Timer timer;
Rectangle2D.Double guy, platform, platform2;
Shape[] shapeArr = new Shape[10];
int dx, dy;
/** Constructor to set up the GUI */
ArrayList myKeys = new ArrayList<Character>();
public static STATE gameState = STATE.PAUSED;
//public static STATE playerState = STATE.ONGROUND;
public PlatformingGame() {
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( CANVAS_WIDTH/2 - 20, CANVAS_HEIGHT, 30, 20);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
timer = new Timer(10, this);
// Set up a panel for the buttons
JPanel btnPanel = new JPanel();
// btnPanel.setPreferredSize(new Dimension(CANVAS_WIDTH/2, CANVAS_HEIGHT));
btnPanel.setLayout(new FlowLayout());
btnStartRestat = new JButton("Start/Restart");
btnExit = new JButton("Exit");
btnPanel.add(btnStartRestat);
btnPanel.add(btnExit);
btnStartRestat.addActionListener(this);
btnExit.addActionListener(this);
// Set up a custom drawing JPanel
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Add both panels to this JFrame
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(btnPanel, BorderLayout.SOUTH);
// "this" JFrame fires KeyEvent
addKeyListener(this);
requestFocus(); // set the focus to JFrame to receive KeyEvent
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Handle the CLOSE button
pack(); // pack all the components in the JFrame
setVisible(true); // show it
}
public void generateSpikes(){
Rectangle2D.Double spikes = null;
for (int i = 0; i < 10; i++) {
spikes = new Rectangle2D.Double (CANVAS_WIDTH - 300 + i*20 , CANVAS_HEIGHT - 30 , 20, 30);
shapeArr[i] = spikes;
}
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==btnStartRestat)
{
generateSpikes();
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( 100, CANVAS_HEIGHT - guy.height, 15, 30);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
gameState = STATE.PLAYING;
}
else if (e.getSource()==btnExit)
{
// requestFocus(); // change the focus to JFrame to receive KeyEvent
}
else if (e.getSource()== timer){
if (isHitDetected(platform2, guy)){
// playerState = STATE.ONGROUND;
guy.y = platform2.y;
}
if (myKeys.contains('a')
&& (guy.x > 0)){
guy.x = guy.x - 5; }
if (myKeys.contains('d')
&& (guy.x < CANVAS_WIDTH - guy.width)){
guy.x = guy.x + 5; }
{
updateGuyPosition();
}
requestFocus();
canvas.repaint();
}
}
public void updateGuyPosition(){
double guyHeight = guy.height;
if (guy.x >= CANVAS_WIDTH - guy.width){
}
if(gameState == STATE.PLAYING) {
guy.y += jumpSpeed;
if (guy.y < groundLevel - guyHeight) {
// if(playerState == STATE.INAIR) {
jumpSpeed += 1;
}
// }
else {
// if(playerState == STATE.INAIR) {
//playerState = STATE.ONGROUND;
jumpSpeed = 0;
guy.y = groundLevel - guyHeight;
}
// }
if (myKeys.contains('w') == true && guy.y == groundLevel - guyHeight) {
jumpSpeed = -15;
// playerState = STATE.INAIR;
}
}
}
public static boolean isHitDetected(Shape shapeA, Shape shapeB) {
Area areaA = new Area(shapeA);
areaA.intersect(new Area(shapeB));
return !areaA.isEmpty();
}
public void keyPressed(KeyEvent evt) {
if (!myKeys.contains(evt.getKeyChar())){
myKeys.add(evt.getKeyChar());
}
}
public void keyReleased(KeyEvent evt) {
myKeys.remove(myKeys.indexOf(evt.getKeyChar()));
}
public void keyTyped(KeyEvent evt) {
}
/** The entry main() method */
public static void main(String[] args) {
PlatformingGame myProg = new PlatformingGame(); // Let the constructor do the job
myProg.timer.start();
}
/**
* DrawCanvas (inner class) is a JPanel used for custom drawing
*/
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(CANVAS_BACKGROUND);
g.setColor(LINE_COLOR);
Graphics2D g2d = (Graphics2D)g;
if(gameState == STATE.PLAYING) {
g2d.fill(guy);
g.setColor(Color.lightGray);
g2d.fill(platform);
g2d.fill(platform2);
for (int i = 0; i < 10; i++) {
g2d.fill(shapeArr[i]);
}
}
if(gameState == STATE.PAUSED) {
g.drawString("Game Paused", CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
}
}
}
}

Calling the methods in a class in Java

I have a very basic question: my MainDriver class wishes to run the Line class when a button Line is pressed; however, I know we cannot run a whole class, so if there's another way to implement this, please let me know.
The following is the MainDriver class; I've highlighted the relevant bit in astericks.
package javafx.scene;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
//import java.awt.*;
class MainDriver extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
// create a frame
static JFrame frame;
// main function
public static void main(String args[])
{
// create a frame
frame = new JFrame("DrawShapes");
try {
// set look and feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
System.err.println(e.getMessage());
}
// create a object of class
Line line = new Line();
// create number buttons and some operators
JButton b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bs, bd, bm, be, beq;
// create number buttons
b0 = new JButton("line");
b1 = new JButton("circle");
b2 = new JButton("triangle");
b3 = new JButton("rectangle");
b4 = new JButton("quadrilateral");
b5 = new JButton("move");
b6 = new JButton("copy");
b7 = new JButton("delete");
b8 = new JButton("random");
b9 = new JButton("import");
ba = new JButton("export");
bs = new JButton("");
bd = new JButton("/");
bm = new JButton("*");
beq = new JButton("C");
// create . button
be = new JButton(".");
// create a panel
JPanel p = new JPanel();
// add action listeners
b0.addActionListener(line);
//add more later
// add elements to panel
p.add(b0);
p.add(ba);
p.add(b1);
p.add(b2);
p.add(b3);
p.add(bs);
p.add(b4);
p.add(b5);
p.add(b6);
p.add(bm);
p.add(b7);
p.add(b8);
p.add(b9);
p.add(bd);
p.add(be);
p.add(b0);
p.add(beq);
// set Background of panel
p.setBackground(Color.blue);
// add panel to frame
frame.add(p);
frame.setSize(450, 400);
}
public void actionPerformed(ActionEvent e)
{
String s = e.getActionCommand();
*************************
if (s.equals("line")) {
//Im not sure how to implement the object here
}
***************************
}
}
And here's the Line class
package javafx.scene;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class Line extends JPanel implements MouseListener,ActionListener{
private int x,y,x2,y2,a=1;
public Line(){
super();
addMouseListener(this);
}
public void paint(Graphics g){
int w = x2 - x ;
int h = y2 - y ;
int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0 ;
if (w<0) dx1 = -1 ; else if (w>0) dx1 = 1 ;
if (h<0) dy1 = -1 ; else if (h>0) dy1 = 1 ;
if (w<0) dx2 = -1 ; else if (w>0) dx2 = 1 ;
int longest = Math.abs(w) ;
int shortest = Math.abs(h) ;
if (!(longest>shortest)) {
longest = Math.abs(h) ;
shortest = Math.abs(w) ;
if (h<0) dy2 = -1 ; else if (h>0) dy2 = 1 ;
dx2 = 0 ;
}
int numerator = longest >> 1 ;
for (int i=0;i<=longest;i++) {
g.fillRect(x,y,1,1);
numerator += shortest ;
if (!(numerator<longest)) {
numerator -= longest ;
x += dx1 ;
y += dy1 ;
} else {
x += dx2 ;
y += dy2 ;
}
}
}
public void mouseClicked(MouseEvent mouse) {
if (a == 1) {
a = 0;
x = x2 = mouse.getX();
y = y2 = mouse.getY();
} else {
a = 1;
x = x2;
y = y2;
x2 = mouse.getX();
y2 = mouse.getY();
repaint();
}
}
public void mouseEntered(MouseEvent mouse){ }
public void mouseExited(MouseEvent mouse){ }
public void mousePressed(MouseEvent mouse){ }
public void mouseReleased(MouseEvent mouse){ }
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
Here is an example on how to go about it:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
public class Main {
private static void drawPoint(final Graphics g, final Point p) {
g.drawLine(p.x - 10, p.y, p.x + 10, p.y);
g.drawLine(p.x, p.y - 10, p.x, p.y + 10);
}
private static void drawLine(final Graphics g, final Point p1, final Point p2) {
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
public static interface ShapeByPoints {
int getPointCount();
void draw(final Graphics g, final Point... points);
}
public static class DrawPanel extends JPanel {
private final ArrayList<Point> points;
private ShapeByPoints s;
public DrawPanel() {
points = new ArrayList<>();
s = null;
}
public void setShape(final ShapeByPoints s) {
this.s = s;
points.clear();
repaint();
}
public void modifyLastPoint(final Point p) {
points.get(points.size() - 1).setLocation(p);
repaint();
}
public void addPoint(final Point p) {
if (s != null && points.size() == s.getPointCount())
points.clear();
points.add(p);
repaint();
}
#Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (s != null && s.getPointCount() == points.size())
s.draw(g, points.toArray(new Point[s.getPointCount()]));
else {
points.forEach(p -> drawPoint(g, p));
for (int i = 1; i < points.size(); ++i)
drawLine(g, points.get(i - 1), points.get(i));
}
}
}
public static class EllipseByPoints implements ShapeByPoints {
#Override
public int getPointCount() {
return 2;
}
#Override
public void draw(final Graphics g, final Point... points) {
g.drawOval(Math.min(points[0].x, points[1].x), Math.min(points[0].y, points[1].y), Math.abs(points[1].x - points[0].x), Math.abs(points[1].y - points[0].y));
}
}
public static class PolygonByPoints implements ShapeByPoints {
private final int points;
public PolygonByPoints(final int points) {
this.points = points;
}
#Override
public int getPointCount() {
return points;
}
#Override
public void draw(final Graphics g, final Point... points) {
for (int i = 1; i < this.points; ++i)
drawLine(g, points[i - 1], points[i]);
drawLine(g, points[this.points - 1], points[0]);
}
}
public static class LineByPoints extends PolygonByPoints {
public LineByPoints() {
super(2);
}
}
public static class RectangleByPoints implements ShapeByPoints {
#Override
public int getPointCount() {
return 2;
}
#Override
public void draw(final Graphics g, final Point... points) {
g.drawRect(Math.min(points[0].x, points[1].x), Math.min(points[0].y, points[1].y), Math.abs(points[1].x - points[0].x), Math.abs(points[1].y - points[0].y));
}
}
private static JRadioButton createButton(final String buttonText, final ButtonGroup bg, final DrawPanel dp, final ShapeByPoints s) {
final JRadioButton btn = new JRadioButton(buttonText);
btn.addActionListener(e -> dp.setShape(s));
bg.add(btn);
return btn;
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final DrawPanel dp = new DrawPanel();
final MouseAdapter ma = new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent mevt) {
dp.addPoint(mevt.getPoint());
}
#Override
public void mouseDragged(final MouseEvent mevt) {
dp.modifyLastPoint(mevt.getPoint());
}
#Override
public void mouseReleased(final MouseEvent mevt) {
dp.modifyLastPoint(mevt.getPoint());
}
};
dp.setPreferredSize(new Dimension(500, 350));
dp.addMouseListener(ma);
dp.addMouseMotionListener(ma);
final ButtonGroup bg = new ButtonGroup();
final JPanel buttons = new JPanel();
buttons.add(createButton("Line", bg, dp, new LineByPoints()));
buttons.add(createButton("Ellipse", bg, dp, new EllipseByPoints()));
buttons.add(createButton("Rectangle", bg, dp, new RectangleByPoints()));
buttons.add(createButton("Triangle", bg, dp, new PolygonByPoints(3)));
buttons.add(createButton("Pentagon", bg, dp, new PolygonByPoints(5)));
//... keep creating buttons here ...
final JPanel contents = new JPanel(new BorderLayout());
contents.add(dp, BorderLayout.CENTER);
contents.add(buttons, BorderLayout.PAGE_START);
final JFrame frame = new JFrame("Clicking shapes.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Notes:
Don't use paint unless there is good reason, which usually isn't. In most cases you want to draw the panel, in which case paintComponent should be enough.
Dont' forget to firstly call super.paintComponent inside paintComponent override. This should be the first call, because it will clear the panel for you from previous drawings.
Decide if you want to add JComponents which will draw the shapes, or draw the shapes yourself in a sub-classed panel. In this case, it seems like you are trying both (because Line extends JPanel and you also override paint). In my opinion, in this case, using an abstraction of a shape to be drawn between some points will do the job. That's why I created ShapeByPoints interface.
Swing is not thread safe, which means there can be conditions between competing accesses of the same variable. To avoid such scenarios, you can run every Swing related operation at the Event Dispatch Thread (or EDT for short). To explicitly make a call in the EDT, invoke a method like SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, EventQueue.invokeLater and so on... There is enough material on the Internet about this topic. For example here.
Basically everything is redesigned from scratch in my approach (ie I did not modify your example code, because I guessed it would take a little bit more time, but that's just a guess).
I just created the ShapeByPoints interface which specifies how a shape is supposedly drawn (ie number of points it needs, and a draw method to do the drawing).
Then I created a DrawPanel extends JPanel which contains the state of each operation. For example if the user selects a pentagon to be drawn, he needs 5 points, but what happens when he/she has clicked only twice?... The DrawPanel is responsible for such scenarios and also for drawing the given shape when all the points are completed/clicked.
I added an instance of a DrawPanel in the frame, a MouseAdapter for user interaction and a couple of buttons to demonstrate this logic.
All you need to do now, is to implement ShapeByPoints as you like and supply an instance of it to the DrawPanel depending of the button pressed. I already did some examples on how to do it in the code (like an EllipseByPoints, LineByPoints, RectangleByPoints and PolygonByPoints).
Finally, as a bonus, I added the ability to drag the clicked points (ie not only click them, but click-and-drag them).
Hope it helps.

repaint() paints slower than paintComponent()?

I am painting vehicle objects that I defined using the paintComponent().
Because the vehicles can move, I implement ActionListener and set a Timer() to trigger.
As a result, my vehicles can move. But it is kind of "shaking". When I keep resizing the window to call the paintComponent(), the movement becomes smooth. When I do not resize the window (not calling paintComponent), it gets skaking again. Why? How to fix it?
public class VehiclesComponent extends JComponent implements ActionListener{
private Vehicle[] vehicles;
private Timer timer;
public VehiclesComponent(int n){
vehicles = Vehicle.generateVehicle(n);
timer = new Timer(5,this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (int i=0; i<vehicles.length; i++) {
vehicles[i].draw(g2);
}
// may change later
timer.start();
}
#Override
public void actionPerformed(ActionEvent e){
//check collision in here
for (Vehicle v : vehicles) {
if (Vehicle.intersectsOther(v, vehicles)) {
v.collisionSideEffect();
}
}
//move all in here
for (Vehicle v : vehicles ) {
v.move();
}
repaint();
//?? repaint slower than paintComponent
}
}
Start by taking a look at Painting in AWT and Swing. Remember, repaint is only a suggest made to the RepaintManager, the RepaintManager may choose to consolidate multiple repaint calls into a smaller number of actual paint events.
Make sure you are calling super.paintComponent, otherwise you will end up with no end of strange paint artifacts.
Don't, directly or indirectly, modify the state of the component or ant other components from within any paint method, this will result in a new repaint request been made, which could lead to a cycle of paint events which could consume your CPU cycles. This means, don't call timer.start()!
Without a runable example to go by, I hobbled this together. Now this is animating 10, 000 individual Vehicles (rectangles), so it's massively over kill, but it should provide the point...
(the gif is only running at 7fps, not your 200fps)
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.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
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 VehiclesComponent(10000));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class VehiclesComponent extends JComponent implements ActionListener {
private Vehicle[] vehicles;
private Timer timer;
public VehiclesComponent(int n) {
vehicles = Vehicle.generateVehicle(n, getPreferredSize());
timer = new Timer(5, this);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < vehicles.length; i++) {
vehicles[i].draw(g2);
}
}
#Override
public void actionPerformed(ActionEvent e) {
//check collision in here
// for (Vehicle v : vehicles) {
// if (Vehicle.intersectsOther(v, vehicles)) {
// v.collisionSideEffect();
// }
// }
//move all in here
for (Vehicle v : vehicles) {
v.move(this.getSize());
}
repaint();
//?? repaint slower than paintComponent
}
}
public static class Vehicle {
protected static final int SIZE = 5;
protected static final Color[] COLORS = new Color[]{
Color.BLACK,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GREEN,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.RED,
Color.WHITE,
Color.YELLOW
};
private int x = 0;
private int y = 0;
private int xDelta;
private int yDelta;
private Shape car;
private Color color;
public static Vehicle[] generateVehicle(int count, Dimension bounds) {
Vehicle[] vehicles = new Vehicle[count];
for (int index = 0; index < vehicles.length; index++) {
vehicles[index] = new Vehicle(bounds);
}
return vehicles;
}
public Vehicle(Dimension size) {
x = (int)(Math.random() * (size.width - SIZE));
y = (int)(Math.random() * (size.height - SIZE));
xDelta = (int)(Math.random() * 3) + 1;
yDelta = (int)(Math.random() * 3) + 1;
car = new Rectangle(SIZE, SIZE);
color = COLORS[(int)(Math.random() * COLORS.length)];
}
public void move(Dimension size) {
x += xDelta;
y += yDelta;
if (x < 0) {
x = 0;
xDelta *= -1;
} else if (x + SIZE > size.width) {
x = size.width - SIZE;
xDelta *= -1;
}
if (y < 0) {
y = 0;
yDelta *= -1;
} else if (y + SIZE > size.height) {
y = size.height - SIZE;
yDelta *= -1;
}
}
public void draw(Graphics2D g2) {
g2.translate(x, y);
g2.setColor(color);
g2.fill(car);
g2.translate(-x, -y);
}
}
}
You could also take a look at this example which renders upwards of 4500 images in random directions and demonstrates some optimisation techniques.
You can also take a look at this example which is capable of animating both in direction and rotation, upwards of 10, 000 images

Java - Removing my 'worm' from an arraylist and JFrame

My program creates randomly colored and sized worms that expand on a JFrame/JPanel. As time progresses the worms are constantly expanding in random directions. When new worm is clicked a new worm is born somewhere on the screen.
Where my issue arises:
I having trouble understanding how I would then kill worms. When I click the kill worm button I want the worm to disappear (OR stop growing) on screen and it to be removed from the arraylist. I have no idea how to even begin doing this. I personally think removing an instance of the arraylist would be the best way, but how would I go about actually removing the worm from the screen.
Below is my code:
Main Class:
package Main;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
ThreadFrame myFrame = new ThreadFrame();
myFrame.setSize(new Dimension(640, 480));
myFrame.setLocationRelativeTo(null);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setTitle("Worms! - Jonathan Perron");
myFrame.setVisible(true);
myFrame.setResizable(false);
}
}
ThreadFrame Class:
package Main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThreadFrame extends JFrame implements ActionListener {
int index = 0;
JButton btnNewWorm, btnKillWorm;
JPanel myPanel2 = new JPanel();
ArrayList<DrawThread> worms = new ArrayList<DrawThread>();
public JPanel getMyPanel2(){
return this.myPanel2;
}
public ThreadFrame() {
JPanel myPanel = new JPanel();
btnNewWorm = new JButton("New Worm");
btnKillWorm = new JButton("Kill Worm");
myPanel.setBounds(0, 400, 640, 80);
myPanel.setLayout(new FlowLayout());
myPanel2.setSize(new Dimension(640, 400));
myPanel2.setLayout(null);
myPanel2.setBackground(Color.WHITE);
btnNewWorm.setBounds(100, 410, 200, 30);
btnKillWorm.setBounds(340, 410, 200, 30);
add(btnNewWorm);
add(btnKillWorm);
add(myPanel2);
add(myPanel);
btnNewWorm.addActionListener(this);
btnKillWorm.addActionListener(this);
}
public void actionPerformed(ActionEvent AE) {
if(AE.getSource() == btnNewWorm){
DrawThread dw = new DrawThread(myPanel2);
worms.add(dw);
System.out.println("New worm!");
}
if(AE.getSource() == btnKillWorm){
//stop worms from growing or complete disappear from JFrame
System.out.println("Kill worm!");
}
}
}
DrawThread Class:
package Main;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import javax.swing.JPanel;
public class DrawThread extends Thread implements Runnable{
Random rand = new Random();
JPanel panel2 = new JPanel();
Graphics2D g, graph;
private int sleepTime, wormDiameter, hue, saturation, brightness, randomWidth, randomHeight;
public DrawThread(int sleepTime, int wormDiameter, int hue, int saturation, int brightness, int randomWidth, int randomHeight, JPanel myPanel2) {
this.sleepTime = sleepTime;
this.wormDiameter = wormDiameter;
this.brightness = brightness;
this.hue = hue;
this.saturation = saturation;
this.randomWidth = randomWidth;
this.randomHeight = randomHeight;
g = (Graphics2D) myPanel2.getGraphics();
}
public void setColor(int hue){
this.hue = hue;
}
public int getSleepTime(){
return sleepTime;
}
public void setSleepTime(int sleepTime){
this.sleepTime = sleepTime;
}
public DrawThread(JPanel myPanel2){
//get panel dimensions
int panelWidth = myPanel2.getWidth();
int panelHeight = myPanel2.getHeight();
//worm location
randomWidth = rand.nextInt(panelWidth);
randomHeight = rand.nextInt(panelHeight);
//worm size
wormDiameter = rand.nextInt(7)+3;
//worm color
hue = rand.nextInt(255);
saturation = rand.nextInt(255);
brightness = rand.nextInt(255);
Color color = new Color(hue, saturation, brightness);
//sleep
sleepTime = rand.nextInt(80) + 20;
//Graphics
g = (Graphics2D) myPanel2.getGraphics();
g.setColor(color);
Ellipse2D.Double ellipse2D = new Ellipse2D.Double(randomWidth, randomHeight, wormDiameter, wormDiameter);
g.fill(ellipse2D);
Thread thread1 = new Thread(new DrawThread(sleepTime, wormDiameter, hue, saturation, brightness, randomWidth, randomHeight, myPanel2));
thread1.start();
}
public void run(){
try {
while(true) {
Thread.sleep(sleepTime);
Color color = new Color(hue, saturation, brightness);
g.setColor(color);
int addedHeight = 0, addedWidth = 0;
int random = rand.nextInt(8);
//determining the worms next move location
if(random == 0){ addedWidth = 0; addedHeight = 1; } //North
if(random == 1){ addedWidth = 1; addedHeight = 1; } //North-East
if(random == 2){ addedWidth = 1; addedHeight = 0; } //East
if(random == 3){ addedWidth = 1; addedHeight = -1; } //South-East
if(random == 4){ addedWidth = 0; addedHeight = -1; } //South
if(random == 5){ addedWidth = -1; addedHeight = -1; } //South-West
if(random == 6){ addedWidth = -1; addedHeight = 0; } //West
if(random == 7){ addedWidth = -1; addedHeight = 1; } //North-West
//Prevent worms from getting off the screen
if(randomHeight >= 480){ addedHeight = -1; }
if(randomHeight <= 0){ addedHeight = 1; }
if(randomWidth >= 640){ addedWidth = -1; }
if(randomWidth <= 0){ addedWidth = 1; }
randomWidth += addedWidth;
randomHeight += addedHeight;
Ellipse2D.Double e = new Ellipse2D.Double(randomWidth, randomHeight, wormDiameter, wormDiameter);
g.fill(e);
}
}
catch (InterruptedException e) {
System.out.println("ERROR!");
}
}
public String toString() {
String result = "SleepTime: " + sleepTime + "\nWorm Diameter: " + wormDiameter
+ "\nHue: " + hue + "\nSaturation: " + saturation + "\nBrightness: "
+ brightness + "\nWidth: " + randomWidth + "\nHeight: " + randomHeight;
return result;
}
}
Any help is greatly appreciated! :)
EDIT: This is the assignment that my teacher has given to write this program.
===========================================================================
In this assignment, we’re going to write a program that draws images of “worms” in a window. The
worms will grow with time, moving in random directions. Each worm will be a different color and will
grow at a different rate. A separate Thread object will manage the drawing of each worm. Here’s an
example of what the window will look like after two worms have grown for a while.
Write a class called ThreadFrame that extends JFrame. This class should include a main method that
creates one instance of this class. This should produce a GUI with an appearance similar to what you see
above. Make the window 640 by 480 pixels, and do not allow the user to resize it. Add two JPanels to
the content pane, a white one in the center region on which the threads will be drawn, and a gray one in
the south region to hold the JButtons marked “New Worm” and “Kill Worm”.
Add an action listener to the “New Worm” button, so that when you click on it, it creates a new instance
of a class called DrawThread (to be described shortly), adds it to an ArrayList, and starts it. Add an action
listener to the “Kill Worm” button, so that when you click on it, it removes the first DrawThread from
the ArrayList and interrupts it.
The class DrawThread extends Thread, and does most of the work of the program. This class will draw
on the upper panel of the ThreadFrame, so a reference to this panel must be passed to the constructor
of DrawThread, when this constructor is called from ThreadFrame. The constructor should perform the
following tasks:
Assign the JPanel reference (received as an argument) to an instance variable of this object.
Get the graphics context for the JPanel (use the getGraphics method), cast it to type Graphics2D, and
assign it to an instance variable.
Determine the width and height of this JPanel, and save these values.
Create a Color object, with randomly-chosen values for the three arguments to set the red, green, and
blue intensities, and assign this object to an instance variable.
Randomly choose a sleep time for this thread, between 20 and 100 milliseconds. This will determine
how rapidly the image grows.
Regarding your instructions
Write a class called ThreadFrame that extends JFrame. This class should include a main method that creates one instance of this class. This should produce a GUI with an appearance similar to what you see above. Make the window 640 by 480 pixels, and do not allow the user to resize it. Add two JPanels to the content pane, a white one in the center region on which the threads will be drawn, and a gray one in the south region to hold the JButtons marked “New Worm” and “Kill Worm”.
OK, you've got this.
Add an action listener to the “New Worm” button, so that when you click on it, it creates a new instance of a class called DrawThread (to be described shortly), adds it to an ArrayList, and starts it.
Again, you've done this.
Add an action listener to the “Kill Worm” button, so that when you click on it, it removes the first DrawThread from the ArrayList and interrupts it.
Break it down:
Get the most recent worm from the ArrayList -- you would use two ArrayList methods, size() and get(...) to achieve this. Give it a try.
Then interrupt the thread. Once you get the object from the array list, you will need to call a Thread method on it, and I'm guessing that you'll be able figure out which method, right (read the instructions for this, i.e, "and interrupts it")? ;)
Edit
Note, that his recommendations are not good, and I would not hire your instructor or course director as a Swing programmer if I needed one.
Edit
Just for grins, here is another way to code this sort of thing. Note that it does not satisfy your assignment requirements (which is one reason I don't hesitate to post it), but it shows what I believe are better Swing behaviors:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class MyWormMain {
private static void createAndShowGui() {
MyWormDrawPanel drawPanel = new MyWormDrawPanel();
MyWormButtonPanel btnPanel = new MyWormButtonPanel(drawPanel);
JFrame frame = new JFrame("Worms");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
frame.getContentPane().add(btnPanel.getMainPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyWormDrawPanel extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = 480;
private static final Color BACKGROUND = Color.WHITE;
private static final int TIMER_DELAY = 50;
private List<MyWorm> wormList = new ArrayList<>();
private Timer wormTimer;
private Random random = new Random();
public MyWormDrawPanel() {
setBackground(BACKGROUND);
wormTimer = new Timer(TIMER_DELAY, new WormTimerListener());
wormTimer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (MyWorm worm : wormList) {
worm.draw(g2);
}
}
public void addWorm() {
int r = random.nextInt(128) + 128;
int g = random.nextInt(128) + 128;
int b = random.nextInt(128) + 128;
int rand = random.nextInt(3);
switch (rand) {
case 0:
r /= 3;
break;
case 1:
g /= 3;
break;
case 2:
b /= 3;
default:
break;
}
Color color = new Color(r, g, b);
int x = random.nextInt(PREF_W);
int y = random.nextInt(PREF_H);
Point head = new Point(x, y);
wormList.add(new MyWorm(color, head, PREF_W, PREF_H));
}
public void killWorm() {
if (wormList.size() > 0) {
wormList.remove(wormList.size() - 1);
}
}
private class WormTimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (MyWorm worm : wormList) {
worm.grow();
}
repaint();
};
}
}
#SuppressWarnings("serial")
class MyWormButtonPanel {
private static final int GAP = 15;
private JPanel mainPanel = new JPanel();
private MyWormDrawPanel drawPanel;
public MyWormButtonPanel(MyWormDrawPanel drawPanel) {
this.drawPanel = drawPanel;
mainPanel.setLayout(new GridLayout(1, 0, GAP, GAP));
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(new JButton(new AddWormAction("Add Worm", KeyEvent.VK_A)));
mainPanel.add(new JButton(new KillWormAction("Kill Worm", KeyEvent.VK_K)));
}
public JComponent getMainPanel() {
return mainPanel;
}
private class AddWormAction extends AbstractAction {
public AddWormAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.addWorm();
}
}
private class KillWormAction extends AbstractAction {
public KillWormAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.killWorm();
}
}
}
class MyWorm {
private static final int MAX_DIR = 360;
private static final int SEG_WIDTH = 20;
private static final int MAX_RAND_DIR = 60;
private Color color;
private List<Point> body = new ArrayList<>();
private Random random = new Random();
private int direction;
private int maxX;
private int maxY;
public MyWorm(Color color, Point head, int maxX, int maxY) {
this.color = color;
body.add(head);
direction = random.nextInt(MAX_DIR);
this.maxX = maxX;
this.maxY = maxY;
}
public void grow() {
Point lastPt = body.get(body.size() - 1);
int x = lastPt.x
+ (int) (SEG_WIDTH * 3 * Math.cos(Math.toRadians(direction)) / 4.0);
int y = lastPt.y
+ (int) (SEG_WIDTH * 3 * Math.sin(Math.toRadians(direction)) / 4.0);
if (x < 0) {
x = maxX - 1;
}
if (x > maxX) {
x = 0;
}
if (y < 0) {
y = maxY - 1;
}
if (y > maxY) {
y = 0;
}
Point nextPoint = new Point(x, y);
direction += random.nextInt(MAX_RAND_DIR) - MAX_RAND_DIR / 2;
body.add(nextPoint);
}
public void draw(Graphics2D g2) {
Graphics2D g2b = (Graphics2D) g2.create();
g2b.setColor(color);
for (Point p : body) {
int x = p.x - SEG_WIDTH / 2;
int y = p.y - SEG_WIDTH / 2;
int width = SEG_WIDTH;
int height = SEG_WIDTH;
g2b.fillOval(x, y, width, height);
}
g2b.dispose();
}
}

How to move the image inside the JApplet in vertical line?

I have displayed an image(ball) inside the JApplet, now I want the image to move in a vertical way (up and down). The problem is I don't know how to do it.
Could someone has an idea about this matter?
You need to set the position of that image to some calculated value (means you caculate the vertical position using time, speed and maybe other restrictions).
How you'd set that position depends on how you draw the image.
Example, based on drawing in the applet's (or a nested component's) paint(Graphics g) method:
//first calculate the y-position
int yPos += timeSinceLastPaint * speed; //increment the position
if( (speed > 0 && yPos > someMaxY) || (speed < 0 && yPos <0 ) ) {
speed *= -1; //if the position has reached the bottom (max y) or the top invert the direction
}
//in your paint(Graphics g) method:
g.drawImage(image, yPos, x, null);
Then you'd have to constantly repaint the applet.
More information on animations in applets can be found here: http://download.oracle.com/javase/tutorial/uiswing/components/applet.html
another example for javax.swing.Timer with moving Ojbects created by paintComponent(Graphics g), and I have lots of Start, not some blurred Mikado :-)
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class AnimationBackground {
private Random random = new Random();
private JFrame frame = new JFrame("Animation Background");
private final MyJPanel panel = new MyJPanel();
private JLabel label = new JLabel("This is a Starry background.", JLabel.CENTER);
private JPanel stopPanel = new JPanel();
private JPanel startPanel = new JPanel();
public AnimationBackground() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
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));
label.setForeground(Color.WHITE);
panel.add(label);
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);
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.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
AnimationBackground aBg = new AnimationBackground();
}
});
}
private 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;
}
}
private 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(512, 512));
}
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);
}
}
}
}
How to move the image inside the JApplet ..?
Pretty much exactly the same way you might do it in a JFrame, JComponent or JPanel or...
Or to put that another way, nothing to do with applets and everything to do with Graphics2D. For more details, see the 2D Graphics Trail of the Java Tutorial.
When you've figured how to move an image and paint it to a Graphics2D, implement that logic in a JComponent or JPanel's paintComponent(Graphics) method and drop the component with moving image into a JApplet or JFrame (or a JPanel etc.).
For the animation side of it, use a javax.swing.Timer as seen in this example. This example does not extend any component. Instead, it creates a BufferedImage and adds it to a JLabel that is displayed to the user. When the timer fires, the code grabs the Graphics object of the image, and proceeds from there to draw the bouncing lines.
import java.awt.image.BufferedImage;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import javax.swing.*;
import java.util.Random;
class LineAnimator {
public static void main(String[] args) {
final int w = 640;
final int h = 480;
final RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
hints.put(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY
);
final BufferedImage bi = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB);
final JLabel l = new JLabel(new ImageIcon(bi));
final BouncingLine[] lines = new BouncingLine[100];
int factor = 1;
for (int ii=0; ii<lines.length; ii++) {
lines[ii] = new BouncingLine(w*factor,h*factor);
}
final Font font = new Font("Arial", Font.BOLD, 30);
ActionListener al = new ActionListener() {
int count = 0;
long lastTime;
String fps = "";
private final BasicStroke stroke = new BasicStroke(6);
public void actionPerformed(ActionEvent ae) {
count++;
Graphics2D g = bi.createGraphics();
g.setRenderingHints(hints);
g.setColor(new Color(55,12,59));
g.fillRect(0,0,w,h);
g.setStroke(stroke);
for (int ii=0; ii<lines.length; ii++) {
lines[ii].move();
lines[ii].paint(g);
}
if ( System.currentTimeMillis()-lastTime>1000 ) {
lastTime = System.currentTimeMillis();
fps = count + " FPS";
count = 0;
}
g.setColor(Color.YELLOW);
g.setFont(font);
g.drawString(fps,5,h-5);
l.repaint();
g.dispose();
}
};
Timer timer = new Timer(25,al);
timer.start();
JOptionPane.showMessageDialog(null, l);
//System.exit(0);
timer.stop();
}
}
class BouncingLine {
private final Color color;
private static final Random random = new Random();
Line2D line;
int w;
int h;
int x1;
int y1;
int x2;
int y2;
BouncingLine(int w, int h) {
line = new Line2D.Double(random.nextInt(w),random.nextInt(h),random.nextInt(w),random.nextInt(h));
this.w = w;
this.h = h;
this.color = new Color(
random.nextInt(255)
,random.nextInt(255)
,random.nextInt(255)
,64+random.nextInt(128)
);
x1 = (random.nextBoolean() ? 1 : -1);
y1 = (random.nextBoolean() ? 1 : -1);
x2 = -x1;
y2 = -y1;
}
public void move() {
int tx1 = 0;
if (line.getX1()+x1>0 && line.getX1()+x1<w) {
tx1 = (int)line.getX1()+x1;
} else {
x1 = -x1;
tx1 = (int)line.getX1()+x1;
}
int ty1 = 0;
if (line.getY1()+y1>0 && line.getY1()+y1<h) {
ty1 = (int)line.getY1()+y1;
} else {
y1 = -y1;
ty1 = (int)line.getY1()+y1;
}
int tx2 = 0;
if (line.getX2()+x2>0 && line.getX2()+x2<w) {
tx2 = (int)line.getX2()+x2;
} else {
x2 = -x2;
tx2 = (int)line.getX2()+x2;
}
int ty2 = 0;
if (line.getY2()+y2>0 && line.getY2()+y2<h) {
ty2 = (int)line.getY2()+y2;
} else {
y2 = -y2;
ty2 = (int)line.getY2()+y2;
}
line.setLine(tx1,ty1,tx2,ty2);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(color);
//line.set
g2.draw(line);
}
}
Update 1
I want to do it in JApplet(1) using the image(2), is it possible(3)?
The examples by mKorbel and myself feature either an image in a JLabel or custom rendering in a JPanel. In our case, we added the components to a JOptionPane & a JFrame. Either example could be just as easily added to a JApplet, or a JDialog, or as part of another panel, or.. See the Laying Out Components Within a Container lesson & Using Top-Level Containers in the Java Tutorial for more details.
Instead of the stars or lines in our examples, ..paint your image. My example goes so far as to demonstrate how to get the position to bounce around within the bounds of the container.
Sure it is possible, but "Batteries not included". Our intention is to give you some ideas that you can then adapt to your bouncing ball applet. I doubt anyone is going to create an example for you, using balls, in an applet. Though if you post an SSCCE that shows your intent and what you tried, I (and others) would often run with that source. If you want more specific answers, ask a more specific SSCCE. ;)
I want to do it in JApplet.
Why not both? You can have a hybrid application/applet as shown in this animation.

Categories

Resources