super.paintComponent() isn't working as expected - java

I'm trying to draw a shape multiple times inside a JPanel to mimic an animation (a moving shape across it). The problem is that the shape is being redrawn and thus appearing on the screen multiple times on different places, when all i pretend is that only one shape is visible at a time when it's being redrawn.
The method super.paintComponent() should be responsible for repainting JPanel's background and thus, only one shape should be visible when the redrawing is being performed.
I have the following code (it has been reduced/simplified for the sake of simplicity and better understanding):
public class Animated_Shape_Test extends JFrame
{
public static void main(String args[]) throws IOException
{
new Animated_Shape_Test();
}
public Animated_Shape_Test() throws IOException
{
this.setSize(500, 500);
this.setPreferredSize(new Dimension(500, 500));
this.setLocation(new Point(430, 150));
this.setTitle("Database Launcher v1.0");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setVisible(true);
DBPanel panel = new DBPanel();
getContentPane().add(panel, BorderLayout.CENTER);
}
}
final class DBPanel extends JPanel implements Runnable
{
int musicShapePosX = 85;
int musicShapePosY = 100;
int SEGMENT_SHAPE_LENGTH = 50;
int SHAPE_HEIGHT = 10;
float SHAPE_SPEED = 7.5f;
CustomShapeButton musicShapeButton = new CustomShapeButton(musicShapePosX, musicShapePosY, SEGMENT_SHAPE_LENGTH, SHAPE_HEIGHT);
private ArrayList<Shape> shapes = null;
protected DBPanel() throws IOException
{
shapes = new ArrayList();
shapes.add(musicShapeButton);
this.setOpaque(true);
this.setFocusable(true);
startThread();
}
public void startThread()
{
Thread t = new Thread(this);
t.start();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground().darker());
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.BLACK);
g2.draw(musicShapeButton);
}
public void delay(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
}
}
#Override
public void run()
{
while (true)
{
delay(35);
animateButtonShapeMusic();
repaint();
}
}
public void animateButtonShapeMusic()
{
if (musicShapePosY < 228)
{
musicShapePosY = (int)(musicShapePosY + SHAPE_SPEED);
musicShapeButton.drawShape(musicShapePosX, musicShapePosY, SEGMENT_SHAPE_LENGTH, SHAPE_HEIGHT);
}
}
}
I'm getting several shapes being redrawn across the screen (animation).
I expect a single shape being redrawn across the screen (animation).
Thank you in advance.

Related

How to setImage of each words translate into one to another by using imageArray

I made 5 java classes that their goals were to Translate English into French and to setup the image of each words writing in the Jfield1 when you click on the Jbutton.
My applet arrive to translate each English words writing in JField1 into French words in JField2. And I add two more Classes(ImageImplement and ImageInFrame) for setting up the image But unfortunately nothing work. And I really don’t know how to use imageArray.
Please help me!!!
I am sorry my english is not so good.
THIS IS MY APPLET
My first Class is StringArrayEnglishWord
public class StringArrayEnglishWords extends JPanel {
String[] names;
Graphics2D g2d;
public StringArrayEnglishWords(){
EnglishWords();
// drawNames();
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
public void EnglishWords(){
names=new String[16];
names[0]="Tomatoes";
names[1]="Chairs";
names[2]="Car";
names[3]="Computer";
names[4]="Flowers";
names[5]="Family";
names[6]="Sister";
names[7]="Husband";
names[8]="God";
names[9]="Book";
names[10]="Watch";
names[11]="Pencil";
names[12]="Bottle";
names[13]="Map";
names[14]="Wife";
names[15]="Bag";
}
public void drawNames(){
for (int i=0; i<names.length; i++){
g2d.drawString(names[i], 50, (1+i)*16);
}
}
public int indexOfWord(String userInput)
{
for(int i=0;i<names.length;i++)
{
if(userInput.equals(names[i])){return i;}
}
return -1;
}
}
My second classes is StringArrayFrenchWords:
public class StringArrayFrenchWords extends JPanel {
String[] names2;
Graphics2D g2d;
public StringArrayFrenchWords(){
FrenchWorld();
// drawNames();
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
public void FrenchWorld(){
names2=new String[16];
names2[0]="Tomate";
names2[1]="Chaise";
names2[2]="Voiture";
names2[3]="Ordinateur";
names2[4]="Fleurs";
names2[5]="Familles";
names2[6]="Soeur";
names2[7]="Epoux, Mari";
names2[8]="Dieu";
names2[9]="Livre";
names2[10]="Montre, Regarder";
names2[11]="Crayon";
names2[12]="Bouteille";
names2[13]="Carte,plan";
names2[14]="Femmme";
names2[15]="Sac";
}
public void drawNames(){
for (int i=0; i<names2.length; i++){
g2d.drawString(names2[i], 50, (1+i)*16);
}
}
}
My third Classe is extend Japplet (Translator):
public class Translator extends JApplet implements ActionListener {
String StringField1, StringImage;
StringArrayEnglishWords Englishw;
StringArrayFrenchWords Frenchw;
ImageInJframe img;
ImageImplement Images;
Image Image;
JButton[] buttons;
JComboBox[] comboBoxes;
JButton TranslateButton;
JPanel JPanel0,JPanel1;
JPanel buttonPanel;
JPanel comboBoxesPanel;
JTextField field1,field2;
ImageIcon Imageicon;
JLabel ImageLabel;
public void init(){
setUpFields();
Englishw=new StringArrayEnglishWords();
Frenchw=new StringArrayFrenchWords();
img = new ImageInJframe(); // this was for set up the image
setUpimages();// for setup image too
}
public void setUpFields() {
TranslateButton = new JButton("TranslateButton");
field1 = new JTextField(10);
field2 = new JTextField(10);
field2.setEditable(false);
JPanel0 = new JPanel(new FlowLayout());
JPanel0.add(field1);
TranslateButton.addActionListener(this);
field1.addActionListener(this);
field2.addActionListener(this);
JPanel0.add(TranslateButton);
JPanel0.add(field2);
add(JPanel0, BorderLayout.SOUTH);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
public void setUpimages() {//setUp images too
ImageLabel.setIcon((Icon) img);
JPanel1 = new JPanel(new FlowLayout());
JPanel1.add(ImageLabel);
add(JPanel1, BorderLayout.CENTER);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == TranslateButton) {
System.out.println(field1);
StringField1 = field1.getText();
int index = Englishw.indexOfWord(StringField1);//this will give you the index of the word
if (index == -1) {
field2.setText("Word not found.");
System.out.println(field2);
} else {
field2.setText(Frenchw.names2[index]);
System.out.println("English Words=" + field1.getText());
System.out.println("French Words =" + field2.getText());
//setup Image
Image = img.getIconImage();
int index2 = img.indexOfImage(StringImage);
JPanel1.add(img);
}
}
}
}
My two classes was for seting up images bu using JFame and imageArray: ImageInJframe and ImageImplement
public class ImageInJframe extends JFrame {
JFrame Frame;
Image[] pics;
String[] names = {"apple.jpg", "bags.jpg", "bathroom.jpg", "battled.jpg", "car.png",
"chairs.jpg", "Computer.jpg", "family.jpg", "flowers.jpg", "god.jpg", "house.png", "map.jpg"
, "men.jpg", "pencil.jpg", "sisters.jpg", "tomato.jpg", "watch.jpg", "women.jpg", "book.gif"};
final int NUM_PICS=names.length;
Graphics g;
public static void main(String args[])
{
new ImageInJframe().start();
}
public void start()
{
ImageImplement panel = new ImageImplement(new ImageIcon(String.valueOf(pics)).getImage());
add(panel);
setVisible(true);
setSize(400,400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setImage();
}
public void setImage() {
pics = new Image[NUM_PICS];
}
public int indexOfImage(String userInput)
{
for(int i=0;i<pics.length;i++)
{
if(userInput.equals(pics[i])){return i;}
}
return -1;
}
}
ImageImplement extend JPanel:
public class ImageImplement extends JPanel {
Image img;
public ImageImplement(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
Painting occurs on demand, when your paintComponent is called, you are expected to repaint the current state of the UI. Maybe you should start by taking a look at Painting in AWT and Swing and Performing Custom Painting for more detals about how painting works
Basically, from your paintComponent, you need to call draw, but you should pass it the Graphics context that was passed to the paintComponent method. It's dangerous and unwise to maintain a reference to a Graphics context you did not create
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
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 StringArrayEnglishWords());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class StringArrayEnglishWords extends JPanel {
String[] names;
public StringArrayEnglishWords() {
EnglishWords();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawNames(g2d);
g2d.dispose();
}
public void EnglishWords() {
names = new String[16];
names[0] = "Tomatoes";
names[1] = "Chairs";
names[2] = "Car";
names[3] = "Computer";
names[4] = "Flowers";
names[5] = "Family";
names[6] = "Sister";
names[7] = "Husband";
names[8] = "God";
names[9] = "Book";
names[10] = "Watch";
names[11] = "Pencil";
names[12] = "Bottle";
names[13] = "Map";
names[14] = "Wife";
names[15] = "Bag";
}
public void drawNames(Graphics2D g2d) {
for (int i = 0; i < names.length; i++) {
g2d.drawString(names[i], 50, (1 + i) * 16);
}
}
public int indexOfWord(String userInput) {
for (int i = 0; i < names.length; i++) {
if (userInput.equals(names[i])) {
return i;
}
}
return -1;
}
}
}
You should also be careful when modifying the Graphics context, it is shared by all the components which are within the same window, in most cases, I find it useful to take a snapshot of the Graphics context (Graphics#create) and use that, then I don't need to remember to reset it when I'm done.
Applets are also a dead technology, the plugin has been deprecated and is no longer been supported and in most cases, is actively blocked by most browsers. See Java Plugin support deprecated and Moving to a Plugin-Free Web for more details
Updated
Change...
ImageImplement panel = new ImageImplement(new ImageIcon(String.valueOf(pics)).getImage());
add(panel);
to...
JLabel panel = new JLabel(new ImageIcon(names[0]).getImage());
add(panel);
Assuming the image files are in the current directory where the program is been executed from, then it should work. If they are contained within the package with the class files, then you'll need to use Class#getResource to obtain a reference to the the image and pass the resulting URL to ImageIcon
Your ImageImplement panel is doing nothing, so even if it had a proper image to show, it wouldn't show anything.
String.valueOf(pics) makes no sense at all
You've posted a whole bunch of, what seems to be unrelated code and it's difficult to know what problem you're referring to
This...
ImageLabel.setIcon((Icon) img);
Makes no sense, img is an instance of ImageInJFrame, how is that even remotely related to a Icon?
I officially have no idea what you're trying to do

JlayeredPane Transparency setOpaque not working

I am creating a simulation type application, I want one background layer and another layer on top for all of the animations. Im currently using JlayeredPanes but i cannot get the background on the top layer to show as transparent so I can see the background, any help is much appreciated, heres the code:
Background layer
public class SimBackground extends JLayeredPane{
private Model theModel;
private SimulationArea simulationArea;
public SimBackground(Model theModel){
this.theModel=theModel;
setBackground(new Color(0, 230, 0));
setOpaque(true);
setPreferredSize(new Dimension(500,500));
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for(int x=0;x<50;x++){
for(int y=0;y<50;y++){
g.drawRect((x*10), (y*10), 10, 10);
}
}
}
Top layer
public class SimulationArea extends JLayeredPane {
private int SPEED = 100;
private Model theModel;
Timer timer;
public SimulationArea(Model theModel){
this.theModel = theModel;
setPreferredSize(new Dimension(500,500));
setLocation(0,0);
setOpaque(false);
setBackground(new Color(0,0,0,0));
setVisible(true);
//Swing Timer
timer = new Timer(SPEED,new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
update();
repaint();
revalidate();
}
});
}
private void update() {
theModel.update();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
//test get 1 active object
ArrayList<ActiveObject> activeObjects = theModel.getActiveObjects();
//System.out.println(activeObjects.size());
for(int i=0; i<activeObjects.size(); i++){
ActiveObject activeObject = theModel.getActiveObjects().get(i);
int x = activeObject.getCoordinates().getX();
int y = activeObject.getCoordinates().getY();
int size = activeObject.getSize();
g2d.fillRect (x ,y , size, size);
}
}
Can someone please tell me what i'm missing here?
Don't use a JLayeredPane, but if you do need to use JLayeredPane in the future, you will want to read the tutorial here since as per my comment you're not using them correctly at all. Instead I recommend that you simplify by doing all drawing in a single JPanel, drawing your background into a BufferedImage perhaps in the constructor, and then drawing that image and your sprites within the JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SimExample extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color BKGD_COLOR = new Color(0, 230, 0);
private BufferedImage bkgrnd = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
public SimExample() {
Graphics2D g = bkgrnd.createGraphics();
g.setBackground(BKGD_COLOR);
g.clearRect(0, 0, PREF_W, PREF_H);
g.setColor(Color.black);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
g.drawRect((x * 10), (y * 10), 10, 10);
}
}
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (bkgrnd != null) {
g.drawImage(bkgrnd, 0, 0, null);
}
// draw sprites here
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SimExample mainPanel = new SimExample();
JFrame frame = new JFrame("SimExample");
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();
}
});
}
}

shape.intersects function - behavior

i have this code:
public class Intersect extends JFrame {
private boolean collision = false;
public Intersect() {
add(new JPanel() {
#Override
protected void paintComponent(Graphics g) {
Shape oval = new Ellipse2D.Double(50, 50, 200, 200);
Shape rect = new Rectangle2D.Double(200, 200, 200, 200);
Graphics2D g2 = (Graphics2D) g;
g2.draw(oval);
g2.draw(rect);
if(oval.intersects(rect.getBounds())) {
System.out.println("contact");
collision = true;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
});
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
Intersect i = new Intersect();
i.setVisible(true);
if(i.collision == true)
System.out.println("boom");
else System.out.println("no boom");
}
}
result in console:"
no boom
contact
contact
contact"
program keep false value in variable collision for all the time, but why it print "contact" if it dont change variable collision to true? (in condition if(oval.intersects(rect.getBounds())))
Painting happens asynchronously in response to requests from the operating system to paint the window. It doesn't happen immediately when you call setVisible(true);.
So it does set the collision variable to true. It just hasn't happened yet at the time the code in main runs. This is why "contact" is printed after "no boom".
Edit: The way I'd suggest fixing it is to separate the collision logic from the painting code. E.g., declare the Shapes as fields on the frame, so they are available outside the paint method:
class Intersect extends JFrame {
private Shape oval = new Ellipse2D.Double(50, 50, 200, 200);
private Shape rect = new Rectangle2D.Double(200, 200, 200, 200);
The panel's painting method becomes simply:
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.draw(oval);
g2.draw(rect);
}
Then remove the collision variable and make it a method so you can call it at any time:
boolean collision() {
return oval.intersects(rect.getBounds());
}
public static void main(String[] args) {
Intersect i = new Intersect();
i.setVisible(true);
if (i.collision())
System.out.println("boom");
else System.out.println("no boom");
}
Note: There is another (potential) problem with this code. All GUI-related activity is supposed to happen on a dedicated thread, the event dispatch thread. The main method should switch to the event dispatch thread before creating the GUI. To do this, change the beginning of main to this:
public static void main(final String[] args) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
main(args);
}
});
return;
}
Intersect i = new Intersect();
...
That will re-call main on the GUI thread.

Adding multiple graphic objects to one JFrame

Here is my code it is a guy and a background but only one thing shows up at a time or sometimes nothing at all.
I have a brain class, a frame class, a redPlayer class, and a background class.
The way it works is the brain makes a player and a brain and adds it to the frame.
I think it has something to do with layouts but I tried everything but nothing works.
Please Help!!!
Thanks in advance.
here is the brain:
public class Brain
{
private Frame frame;
private static RedPlayer redPlayer;
private Background background;
private SensorKeys sensor;
public Brain()
{
frame = new Frame();
redPlayer = new RedPlayer();
background = new Background();
sensor = new SensorKeys();
frame.addComponent(redPlayer);
frame.addComponent(background);
frame.addKeySensor(sensor);
redPlayer.revalidate();
}
public static void setRedPlayerVelX(double vx)
{
redPlayer.setVelX(vx);
}
public static void setRedPlayerVelY(double vy)
{
redPlayer.setVelY(vy);
}
public static void makeRedPlayerBullet()
{
}
}
`
here is the frame class
public class Frame
{
private JFrame jf;
public Frame()
{
drawFrame();
}
public void drawFrame()
{
jf = new JFrame();
jf.setSize(800, 600);
jf.setLocation(10, 10);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setBackground(Color.WHITE);
jf.setLayout(null);
}
public void addComponent(JComponent jc)
{
jc.setBounds(jc.getX(), jc.getY(), 100, 100);
jf.add(jc);
}
public void addPanel(JPanel jp)
{
jf.add(jp);
}
public void addKeySensor(KeyListener kl)
{
jf.addKeyListener(kl);
}
}
here is the player class:
public class RedPlayer extends JComponent implements ActionListener
{
private int x,y;
private double velX = 0, velY = 0;
private Timer timer = new Timer(2,this);
private Image redplayer;
public RedPlayer()
{
x = 100;
y = 100;
ImageIcon II = new ImageIcon("redPlayerRight.png");
redplayer = II.getImage();
revalidate();
timer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g;
graphics.drawImage(redplayer, x,y, null);
}
public void actionPerformed(ActionEvent arg0)
{
x += velX;
y += velY;
repaint();
revalidate();
}
public void setVelX(double vx)
{
velX = vx;
}
public void setVelY(double vy)
{
velY = vy;
}
}
And Lastly here is the background class:
public class Background extends JComponent
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g;
graphics.setColor(Color.green);
graphics.fillRect(0, 400, 500, 200);
}
}
I think it has something to do with layouts
Yes, you should read the Swing tutorial on Using Layout Managers to better understand how they work and for examples.
The default layout manager for a JFrame is a BorderLayout. You can't just add 3 components to the same area of the BorderLayout.
I don't know what you are trying to accomplish but start simple. Since you have a background the basic code should be something like:
redPlayer = new RedPlayer();
background = new Background();
background.add( redPlayer );
frame.addComponent(background);
So the red player should display on top of the background. And the background is added to the frame.
Of course you must use a proper layout manager for the background. And you must make sure you override the getPreferredSize() method when you do custom painting so the layout manager knows what the size of every component should be.
Get those two components working first, then move on to the 3rd component.

Repaint a JPanel

I would like to repaint my jPanel
I've a App class who handle the screen displaying in this JFrame I add a Board JPanel object who handle all the JPanel.
In the Board class I had
ex = new Explosion(10, 10);
new Thread(ex).start();
And in my Explosion class I have a constructor who crop my sprite file, an overwriting of paint() and :
public void run()
{
while(cursor < (rows*cols))
{
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(cursor);
cursor++;
}
}
The loop is working fine but I have no repaint in my screen , only the first image is display.
What can I do to refresh ?
Thanks
Edit :
Here is my code :
public class Explosion extends JPanel implements Runnable{
private BufferedImage img;
final int width = 320;
final int height = 320;
final int rows = 5;
final int cols = 5;
private int x,y;
private int cursor;
BufferedImage[] sprites = new BufferedImage[rows * cols];
public Explosion(int x, int y)
{
this.x = x;
this.y = y;
try {
try {
this.img = ImageIO.read(new File((this.getClass().getResource("files/explosion2.png")).toURI()));
} catch (URISyntaxException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
cursor = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
sprites[(i * cols) + j] = img.getSubimage(
i * (width/rows),
j * (height/cols),
width/rows,
height/cols
);
}
}
}
public void run()
{
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
cursor++;
repaint();
}
};
while(cursor < (rows*cols))
{
new Timer(50, taskPerformer).start();
if (cursor==(rows*cols)-1)
cursor=0;
}
}
public void paintComponent(Graphics g){
System.out.println("paintComponent");
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(sprites[cursor], x, y, this);
g.dispose();
}
/*public void paint(Graphics g) {
super.paint(g);
System.out.println("paint");
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(sprites[cursor], x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}*/
}
public class Main extends JFrame{
public Main()
{
Board board = new Board();
add(board);
setTitle("Explosion");
setSize(500, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Main();
}
}
public class Board extends JPanel{
Explosion ex;
public Board()
{
setDoubleBuffered(true);
ex = new Explosion(10,10);
new Thread(ex).start();
}
public void paint(Graphics g) {
ex.paintComponent(g);
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
}
#StanislavL (I can't comment yet): No, you don't have to call repaint() in the EDT:
The following JComponent methods are safe to call from any thread: repaint(), revalidate(), and invalidate(). The repaint() and revalidate() methods queue requests for the event-dispatching thread to call paint() and validate(), respectively. The invalidate() method just marks a component and all of its direct ancestors as requiring validation.
Source: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#exceptions
Is cursor declared as volatile? If not, the EDT may not see the changes the thread made to cursor. Therefore, always the first image is painted.
Do not override paint, instead override paintComponent
Do not use Thread.sleep, instead use a utility class, such as javax.swing.Timer to execute a particular action at a specified interval. This will ensure that all changes are done on the EDT and that the waiting occurs in a background thread.
Note that without compilable code, it's hard to tell what the real problem is; this is all guesswork.
Repaint must be called in EDT.
Use SwingUtilities.invokeAndWait() or invokeLater() to call repaint.

Categories

Resources