Simple Java game draws only half window - java

I can not figure out why the game is only drawing only on half the window I make.
I add in actionPerformed to always implement to y position and it goes only on half the window , then the images stopes.
Main
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[]args){
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame ex = new Main();
ex.setVisible(true);
}
});
}
public Main(){
setTitle("Maze");
add(new Game());
pack();
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Game
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Game extends JPanel implements ActionListener {
private final int GWIDTH = 400;
private final int GHEIGHT = 400;
private int GAME_DELAY = 10;
private Timer timer;
private Image player;
/*Player*/
private final int spawnPosition = 0;
int playerX = 0;
int playerY = spawnPosition;
/*Mouse*/
private Mouse m;
public Game(){
setFocusable(true);
setPreferredSize(new Dimension(GWIDTH, GHEIGHT));
addMouseListener(new Mouse());
initTime();
//Importam poza
loadPlayer();
//Mouse
m = new Mouse();
}
private void initTime(){
timer = new Timer(GAME_DELAY, this);
timer.start();
}
private void loadPlayer(){
ImageIcon img = new ImageIcon("smiley.png");
player = img.getImage();
}
public int getX(){ return playerX; }
public int getY() { return playerY; }
private void drawPlayer(Graphics2D g2d){
g2d.drawImage(player,getX(),getY(),null);
Toolkit.getDefaultToolkit().sync();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawPlayer(g2d);
g2d.dispose();
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
playerY += 1;
repaint();
}
}
Image

Related

How to fix flickering of dynamic moving images over a JPanel that is on top of another pre-painted JPanel?

I have made 2 JPanels, Panel and BackGround, in a JFrame. I am dynamically painting the Panel after 10ms(using a Timer), but the BackGround is only painted once at the beginning of the game. The Panel is responsible for the displaying of the fighters(spacecrafts), the projectiles and the aliens. The BackGround is responsible for the displaying of the background scene which is non-dynamic. The paintComponent(Graphics) method does paint the fighters and the projectiles, but flickers when they are updating. Can someone find the cause.
This is my Frame:
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Frame extends JFrame {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1280;
public static final int HEIGHT = 720;
public static final int DELAY = 10;
private Panel panel;
private Background bg;
public Frame() {
panel = new Panel();
bg = new Background();
initComponents();
}
public void initComponents() {
this.setSize(WIDTH, HEIGHT);
this.add(bg);
this.add(panel);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT) panel.moveLeft();
else if(e.getKeyCode() == KeyEvent.VK_RIGHT) panel.moveRight();
}
});
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Frame().setVisible(true);
}
});
}
}
This is my Panel:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Panel extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
public static final int DELAY = Frame.DELAY;
private Timer timer;
private BufferedImage fighter;
int x, y;
public Panel() {
timer = new Timer(DELAY, this);
try {
fighter = ImageIO.read(this.getClass().getResource("fighter.png"));
} catch (IOException e) {
e.printStackTrace();
}
initComponents();
timer.start();
}
public void initComponents() {
this.setSize(Frame.WIDTH, Frame.HEIGHT);
this.setDoubleBuffered(true);
this.setBackground(new Color(0, 0, 0, 0));
x = 150;
y = 200;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
doDrawing(g2d);
}
private void doDrawing(Graphics2D g2d) {
g2d.drawImage(fighter, x, y, null);
}
#Override
public void actionPerformed(ActionEvent arg0) {
this.repaint();
}
public void moveLeft() {
x -= 10;
}
public void moveRight() {
x += 10;
}
}
This is the BackGround:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Background extends JPanel implements ActionListener{
private static final long serialVersionUID = 1L;
private BufferedImage backGround;
private Timer timer;
public Background() {
this.setSize(Frame.WIDTH, Frame.HEIGHT);
this.setBackground(new Color(0, 0, 0, 0));
timer = new Timer(Frame.DELAY, this);
try {
backGround = ImageIO.read(this.getClass().getResource("background.png"));
} catch (IOException e) {
e.printStackTrace();
}
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(backGround, 0, 0, null);
}
#Override
public void actionPerformed(ActionEvent e) {
this.repaint();
}
}
I expect the sprites not to flicker and not to lag(which is not happening after lots of trials).
Do not call repaint within a painting method
Get rid of the Background class and do all drawing in one JPanel. For example:
See example below of both as well as of MCVE design
whole thing can be copy/pasted into IDE and run
uses images available to all online, not on disk
I would also remove the Timer that simply calls repaint() and instead either
call repaint from within the KeyListener
or use the timer to do the actual sprite movement code (with repaint()). This would be useful if you want continuous movement
Example MCVE:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Frame1 extends JFrame {
// Image attribution:
// By Adam Evans - M31, the Andromeda Galaxy (now with h-alpha)
// Uploaded by NotFromUtrecht, CC BY 2.0,
// https://commons.wikimedia.org/w/index.php?curid=12654493
public static final String ANDROMEDA_IMAGE = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/9/98/Andromeda_Galaxy_%28with_h-alpha%29.jpg/"
+ "1280px-Andromeda_Galaxy_%28with_h-alpha%29.jpg";
public static final String SPRITE_IMAGE = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/a/a1/Glossy_3d_blue_blue2.png/" + "120px-Glossy_3d_blue_blue2.png";
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1280;
public static final int HEIGHT = 720;
public static final int DELAY = 10;
private Panel1 panel;
// private Background bg;
public Frame1() {
panel = new Panel1();
// bg = new Background();
initComponents();
}
public void initComponents() {
this.setSize(WIDTH, HEIGHT);
// this.add(bg);
this.add(panel);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
panel.moveLeft();
else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
panel.moveRight();
}
});
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Frame1().setVisible(true);
}
});
}
}
class Panel1 extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
public static final int DELAY = Frame1.DELAY;
private Timer timer;
private BufferedImage fighter;
private BufferedImage background;
int x, y;
public Panel1() {
timer = new Timer(DELAY, this);
try {
URL url = new URL(Frame1.SPRITE_IMAGE);
// fighter = ImageIO.read(this.getClass().getResource("fighter.png"));
fighter = ImageIO.read(url);
url = new URL(Frame1.ANDROMEDA_IMAGE);
background = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
initComponents();
timer.start();
}
public void initComponents() {
this.setSize(Frame1.WIDTH, Frame1.HEIGHT);
this.setDoubleBuffered(true);
this.setBackground(new Color(0, 0, 0, 0));
x = 150;
y = 200;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, this);
g.drawImage(fighter, x, y, this);
}
#Override
public void actionPerformed(ActionEvent arg0) {
this.repaint();
}
public void moveLeft() {
x -= 10;
}
public void moveRight() {
x += 10;
}
}

Mouse listener not working with JPanel

The paintcomponent works fine, the image shows up, no problems on that end or with the JFrame. I want to implement zooming and panning but not getting any luck as the added mouse listener isn't responding.
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import javax.swing.JPanel;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class map extends JPanel {
public int moz = 100;
public void map()
{
addMouseListener(
new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
moz = moz +100;
repaint();
}
}
);
}
public void paintComponent(Graphics g){
.....
g.drawLine( 0, moz, 100, 0 );
}
}
Your class doesn't have a real constructor but rather has a "pseudo" constructor since it has a return type -- yes void counts. So get rid of the void return type by changing:
// this is not a constructor
public void map()
to:
// this is a real constructor
public map()
Also as a side recommendation, change your variable and class names to conform with Java naming conventions: class names all start with an upper-case letter and method/variable names with a lower-case letter.
So in your case you'd name your class Map, and in playing with the code could have something like:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class Map extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color DRAW_RECT_COLOR = new Color(200, 200, 255);
public static final Stroke IMAGE_STROKE = new BasicStroke(3f);
public static final Color IMAGE_COLOR = Color.RED;
private BufferedImage image = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
private Rectangle drawRectangle = null;
private List<Color> colors = new ArrayList<>();
private Random random = new Random();
public Map() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
for (int r = 0; r < 4; r++) {
int r1 = (r * 255) / 3;
for (int g = 0; g < 4; g++) {
int g1 = (g * 255) / 3;
for (int b = 0; b < 4; b++) {
int b1 = (b * 255) / 3;
colors.add(new Color(r1, g1, b1));
}
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
Graphics2D g2 = (Graphics2D) g;
if (drawRectangle != null) {
g.setColor(DRAW_RECT_COLOR);
g2.draw(drawRectangle);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
Point p1 = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 == null) {
return;
}
Point p2 = e.getPoint();
drawRectangle = createDrawRect(p2);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
Rectangle rectangle = createDrawRect(e.getPoint());
Graphics2D g2 = image.createGraphics();
g2.setStroke(IMAGE_STROKE);
Color c = colors.get(random.nextInt(colors.size()));
g2.setColor(c);
g2.draw(rectangle);
g2.dispose();
p1 = null;
drawRectangle = null;
repaint();
}
private Rectangle createDrawRect(Point p2) {
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
return new Rectangle(x, y, w, h);
}
}
private static void createAndShowGui() {
Map mainPanel = new Map();
JFrame frame = new JFrame("Map");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java Animation with ActionListener

So I'm trying to draw 2 circles on top of each other (kinda like a snowman) and move the snowman to the right when the user clicks on the "Start" button and stop moving the snowman when the user clicks on the "Stop" button. However, the only thing that I am able to come up with is 2 snowmen drawn next to each other that don't react to the buttons.
Here is what I've come up with:
import java.awt.Graphics2D;
public interface MoveableShape {
void draw(Graphics2D g);
void translate(int dx, int dy);
}
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class SnowmanShape implements MoveableShape {
private int x;
private int y;
private int width;
public SnowmanShape(int x, int y, int width){
this.x = x;
this.y = y;
this.width = width;
}
#Override
public void draw(Graphics2D g2) {
// TODO Auto-generated method stub
Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 10, 10);
Ellipse2D.Double body = new Ellipse2D.Double(0, 11, 10, 10);
g2.draw(head);
g2.draw(body);
}
#Override
public void translate(int dx, int dy) {
// TODO Auto-generated method stub
x += dx;
y += dy;
}
}
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class MyPanel extends JPanel{
MoveableShape s;
public MyPanel (MoveableShape m){
s = m;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
s.draw((Graphics2D)g);
}
}
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class AnimationTester {
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 200;
private static final int SNOWMAN_WIDTH = 50;
final static MoveableShape shape = new SnowmanShape(0, 0, SNOWMAN_WIDTH);
final static JPanel panel = new MyPanel(shape);
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame frame = new JFrame();
frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
JButton startButton = new JButton("Start");
JButton stopButton = new JButton("Stop");
frame.setLayout(new BorderLayout());
frame.add(panel);
frame.add(startButton, BorderLayout.NORTH);
frame.add(stopButton, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
final int DELAY = 100;
// Milliseconds between timer ticks
Timer t = new Timer(DELAY, translateSnowman());
startButton.addActionListener(startTimer(t));
stopButton.addActionListener(stopTimer(t));
}
public static ActionListener translateSnowman(){
return new ActionListener(){
public void actionPerformed(ActionEvent event){
shape.translate(1, 0);
panel.repaint();
}
};
}
public static ActionListener startTimer(final Timer t){
return new ActionListener(){
public void actionPerformed(ActionEvent event){
t.start();
}
};
}
public static ActionListener stopTimer(final Timer t){
return new ActionListener(){
public void actionPerformed(ActionEvent event){
t.stop();
}
};
}
}
Could someone please let me know where I went wrong or point me in the right direction?
EDIT: I fixed up the AnimationListener so now it doesn't draw 2 snowmans. The snowman still won't move however. I updated the code in the post as well.
Add g2.translate(x, y); to SnowmanShape#draw, before you are painting:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
class SnowmanShape implements MoveableShape {
static final Color headColor = new Color(0xFFE9C9);
static final Color bodyColor = new Color(0xEAF6FF);
static final Color outlineColor = new Color(0x252525);
int x;
int y;
int size;
Ellipse2D.Double head;
Ellipse2D.Double body;
SnowmanShape(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
initModel();
}
void initModel() {
head = new Ellipse2D.Double(0, 0, size, size);
body = new Ellipse2D.Double(0, head.height, size * 1.3d, size * 1.5d);
body.x -= (body.width - head.width) * (1 / 2d);
}
#Override
public void draw(Graphics2D g2) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.translate(x, y);
g2.setColor(headColor);
g2.fill(head);
g2.setColor(outlineColor);
g2.draw(head);
g2.setColor(bodyColor);
g2.fill(body);
g2.setColor(outlineColor);
g2.draw(body);
}
#Override
public void translate(int dx, int dy) {
x += dx;
y += dy;
}
}
I not an expert on doing things like this, but if I were you I would use the timer to move the objects and then call the paint to repaint the objects in a new position. Therefore, your ShapeIcon class would just keep track of the position of your objects. That probably wasn't all that helpful, so to point you in right direction, you can check out some code in this tutorial here.

Use MouseListener to draw circles?

I'm trying to write a program that allows user to specify a circle with 2 mouse presses, the first one on the center and the second on a point on the periphery, and the program I wrote is this.
import javax.swing.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.*;
public class CircleFrame extends JFrame
{
public CircleFrame()
{
circle = new Ellipse2D.Double();
hasCenter = false;
createComponent();
setSize(400, 400);
}
private void createComponent()
{
class CircleComponent extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
circle.setFrame(xTop, yTop, radius*2, radius*2);
g2.draw(circle);
}
}
class MousePressListener1 extends MouseAdapter
{
public void mousePressed(MouseEvent event)
{
if(!hasCenter)
{
xCenter = event.getX();
yCenter = event.getY();
hasCenter = true;
}
}
}
class MousePressListener2 extends MouseAdapter
{
public void mousePressed(MouseEvent event)
{
if (hasCenter)
{
xOut = event.getX();
yOut = event.getY();
xTop = xCenter - Math.abs(xOut - xCenter);
yTop = yCenter - Math.abs(yOut - yCenter);
radius =
Math.sqrt((xOut - xCenter)*(xOut - xCenter) + (yOut - yCenter)*(yOut - yCenter));
hasCenter = false;
}
}
}
addMouseListener(new MousePressListener1());
addMouseListener(new MousePressListener2());
CircleComponent component = new CircleComponent();
add(component);
}
private double xTop;
private double yTop;
private int xCenter;
private int yCenter;
private int xOut;
private int yOut;
private Ellipse2D.Double circle;
private double radius;
private boolean hasCenter;
}
And this is the main class
import javax.swing.JFrame;
public class CircleFrameViewer
{
public static void main(String[] args)
{
JFrame frame = new CircleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Somehow it only shows a blank frame, and no clicks make anything happen.
Anyone can help me?
Don't use two listeners, use one, both listeners will be called whenever a mouse event occurs.
MouseEvents are contextual to the component which generated them. This means you should be adding your listener to the CircleComponent
Make sure you are calling repaint when you want the UI to be updated.
Something like...for example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test2 {
public static void main(String[] args) {
new Test2();
}
public Test2() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point centerPoint;
private Shape circle;
public TestPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (centerPoint == null) {
centerPoint = e.getPoint();
repaint();
} else {
double xTop = Math.min(e.getPoint().x, centerPoint.x);
double yTop = Math.min(e.getPoint().y, centerPoint.y);
double xBottom = Math.max(e.getPoint().x, centerPoint.x);
double yBottom = Math.max(e.getPoint().y, centerPoint.y);
double radius = Math.max(xBottom - xTop, yBottom - yTop);
xTop = centerPoint.x - radius;
yTop = centerPoint.y - radius;
radius *= 2;
circle = new Ellipse2D.Double(xTop, yTop, radius, radius);
repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (circle != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(circle);
g2d.dispose();
}
}
}
}

Painting to a panel using threads in Java

do not know why there is not printing going on here in my run method. I call repaint and override it in the horsethread class. here is my code. When I run the program and hit Run Race it doesnt draw anything to the panel, any ideas?
import javax.swing.JFrame;
public class HorseTester {
public static void main(String[] args)
{
JFrame frame = new HorsePanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.JButton;
import java.awt.GridLayout;
import java.util.ArrayList;
public class HorsePanel extends JFrame
{
private JPanel panel;
private JButton reset;
private JButton quit;
private JButton run;
private ActionListener listener;
private static final int NUM_OF_HORSES = 5;
public static final int FRAME_WIDTH = 400;
public static final int FRAME_HEIGHT = 400;
private ArrayList<Thread> allThreads = new ArrayList<Thread>();
private ArrayList<HorseThread> horses = new ArrayList<HorseThread>();
public HorsePanel()
{
//Allocating the memory for horses
for(int i=0;i<NUM_OF_HORSES;i++)
horses.add(new HorseThread(i+1));
//Adding them to thread pool
for(int i=0;i<NUM_OF_HORSES;i++)
allThreads.add( new Thread(horses.get(i)));
createPanel();
createRunRace();
createQuit();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
}
public void createRunRace()
{
class RunRace implements ActionListener
{
public void actionPerformed(ActionEvent rightEvent)
{
run.setEnabled(false);
for(int i=0;i<NUM_OF_HORSES;i++)
allThreads.get(i).start();
}
}
ActionListener a = new RunRace();
this.run.addActionListener(a);
}
public void createQuit()
{
class QuitRace implements ActionListener
{
public void actionPerformed(ActionEvent rightEvent)
{
System.exit(0);
}
}
ActionListener b = new QuitRace();
this.quit.addActionListener(b);
}
public void createPanel()
{
panel = new JPanel(new BorderLayout());
JPanel drawingPanel = new JPanel();
this.run = new JButton("Run Race");
this.quit = new JButton("Quit");
this.reset = new JButton("Reset");
JPanel topPanel = new JPanel();
topPanel.setLayout(new GridLayout(1, 3));
topPanel.add(run);
topPanel.add(reset);
topPanel.add(quit);
panel.add(topPanel, BorderLayout.NORTH);
panel.add(drawingPanel, BorderLayout.SOUTH);
add(panel);
}
}
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
public class HorseThread extends JComponent implements Runnable
{
public static final int X_START = 10;
public static final int Y_START = 20;
private Horse horse;
private int xpos, ypos;
public HorseThread(int offset)
{
xpos = X_START;
ypos = Y_START * offset;
horse = new Horse(xpos, ypos);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
horse.draw(g2);
}
/**
* Run method that thread executes and makes horses go across
* the screen racing.
*/
public void run()
{
repaint();
}
}
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class Horse
{
private int xTop;
private int yTop;
public static final int RING_WIDTH = 20;
public Horse(int x, int y)
{
xTop = x;
yTop = y;
}
public void setXY(int dx, int dy)
{
xTop = dx;
yTop = dy;
}
public void draw(Graphics2D g2)
{
Ellipse2D.Double horse = new Ellipse2D.Double(xTop, yTop, RING_WIDTH, RING_WIDTH);
g2.setColor(Color.BLUE);
g2.fill(horse);
g2.setColor(Color.WHITE);
g2.fill(horse);
}
}
The main problem is, HorseThread extends from JComponent, but you never actually add it to anything, therefore it never gets painted.
If, instead, you created a TrackPane and painted each of the horses within the paintComponent method (there's no need for HorseThread to extend from JComponent), you might have better luck.
Also note, that once a Thread has completed, it can not be restarted...
For example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class HorseTester {
public static void main(String[] args) {
new HorseTester();
}
public HorseTester() {
JFrame frame = new HorsePanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public class HorsePanel extends JFrame {
private JPanel panel;
private JButton reset;
private JButton quit;
private JButton run;
private ActionListener listener;
public static final int FRAME_WIDTH = 400;
public static final int FRAME_HEIGHT = 400;
private TrackPane trackPane;
public HorsePanel() {
createPanel();
createRunRace();
createQuit();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
}
public void createRunRace() {
class RunRace implements ActionListener {
public void actionPerformed(ActionEvent rightEvent) {
run.setEnabled(false);
trackPane.start();
}
}
ActionListener a = new RunRace();
this.run.addActionListener(a);
}
public void createQuit() {
class QuitRace implements ActionListener {
public void actionPerformed(ActionEvent rightEvent) {
System.exit(0);
}
}
ActionListener b = new QuitRace();
this.quit.addActionListener(b);
}
public void createPanel() {
panel = new JPanel(new BorderLayout());
trackPane = new TrackPane();
this.run = new JButton("Run Race");
this.quit = new JButton("Quit");
this.reset = new JButton("Reset");
JPanel topPanel = new JPanel();
topPanel.setLayout(new GridLayout(1, 3));
topPanel.add(run);
topPanel.add(reset);
topPanel.add(quit);
panel.add(topPanel, BorderLayout.NORTH);
panel.add(trackPane, BorderLayout.CENTER);
add(panel);
}
}
public class TrackPane extends JPanel {
private static final int NUM_OF_HORSES = 5;
private ArrayList<HorseThread> horses = new ArrayList<HorseThread>();
private ArrayList<Thread> threads = new ArrayList<Thread>(25);
public TrackPane() {
setBackground(Color.GREEN);
reset();
}
public void reset() {
// Should dispose of any running threads...
horses.clear();
//Allocating the memory for horses
for (int i = 0; i < NUM_OF_HORSES; i++) {
horses.add(new HorseThread(this, i + 1));
}
}
public void start() {
// Should dispose of any running threads...
threads.clear();
for (int i = 0; i < horses.size(); i++) {
Thread thread = new Thread(horses.get(i));
thread.start();
threads.add(thread);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (HorseThread horse : horses) {
horse.paint(g);
}
}
}
public class HorseThread implements Runnable {
public static final int X_START = 10;
public static final int Y_START = 20;
private Horse horse;
private int xpos, ypos;
private TrackPane track;
public HorseThread(TrackPane track, int offset) {
xpos = X_START;
ypos = Y_START * offset;
horse = new Horse(xpos, ypos);
this.track = track;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
horse.draw(g2);
}
/**
* Run method that thread executes and makes horses go across the screen
* racing.
*/
public void run() {
track.repaint();
}
}
public class Horse {
private int xTop;
private int yTop;
public static final int RING_WIDTH = 20;
public Horse(int x, int y) {
xTop = x;
yTop = y;
}
public void setXY(int dx, int dy) {
xTop = dx;
yTop = dy;
}
public void draw(Graphics2D g2) {
Ellipse2D.Double horse = new Ellipse2D.Double(xTop, yTop, RING_WIDTH, RING_WIDTH);
g2.setColor(Color.BLUE);
g2.fill(horse);
g2.setColor(Color.WHITE);
g2.draw(horse);
}
}
}
Also note that Swing is not thread safe, be careful using Threads in this environment ;)

Categories