I have a script that cycles (almost like a slideshow) through a Vector object (flipBook), using a Thread (animationThread), and adds them to a JPanel. However, the added image is only 2x2 pixels large.
I've verified the images are 50x50, but they don't appear to be properly showing.
Here's some of the code going on behind the Thread instance. I'm not entirely sure which code would be beneficial for finding the source for.
public void startThread() {
if (flipWidth != 0 && flipHeight != 0) {
System.out.println("[ AnimationAsset ] " + "We're starting the thread");
Runnable r = new Runnable() {
#Override
public void run() {
runWork();
}
};
animationThread = new Thread(r, "AnimationThread");
animationThread.start();
going = true;
}
}
private void runWork() {
try {
while (going) {
repaint();
flipIndex = (flipIndex + 1) % numFlips;
System.out.println("[ AnimationAsset ] flipIndex: " + flipIndex);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("[ AnimationAsset ] " + "Interrupted");
}
}
public void paint(Graphics g) {
update(g);
}
public void update(Graphics g) {
System.out.println("[ AnimationAsset ] " + flipIndex);
((Graphics2D) g).drawImage(flipBook.get(flipIndex), null, 5, 5);
}
and adds them to a JPanel
This is not a Swing code. This is AWT code.
You would never override the update() and paint() methods this way when using Swing. Get rid of this code and start over.
To do this in Swing I would use a JLabel with an Icon and add the label to the frame.
Then, to do animation in SWing your should use a Swing Timer.
When the timer fires you simply use the setIcon(...) method of the label to replace the old icon with your new icon.
Emm you have a strange drawing code as
((Graphics2D) g).drawImage(flipBook.get(flipIndex), null, 5, 5);
You can see the docs here... to use Graphic2D drawImage() method right
the most common way of image drawing is to paint image right on JComponent, as a rule, the JLabel. Here is a component example
public class MyLabel extends JLabel
{
private Image image;
public MyLabel(Image image)
{
this.image=image;
}
public void paintComponent(Graphics g)
{
g.drawImage(this.image,x,y,width,height,null);
}
}
so here you can use the component as a common swing object
public class MyPanel extends JPanel
{
public MyPanel()
{
Image image=null;
try{
image=ImageIO.read(new File("image.png"));
}
catch (IOException e) {
}
this.add(new MyLabel(image));
}
}
Good luck
Related
I'm Trying to Animate a seagull image on a JPanel for a game I'm building. The animation works great, it looks how I want it to, but when I click the play button to switch cards to the next JPanel, (There is a play button controlled by the JFrame containing this panel that changes the card to another JPanel, this lags when the animation is going) it lags when the animation is running. Is there a more performance friendly way to run my animation than by looping through an ImageIcon[] like I'm doing?
public class StartPanel extends JPanel implements ActionListener{
Image gull;
Timer timer;
ImageIcon[] seagullAnimation = new ImageIcon[9];
int counter = 0;
StartPanel(){
seagullAnimation[0] = new ImageIcon(getClass().getResource("gullBlink0.png"));
//Here I add the rest of the images in the same fashion
timer = new Timer(13, this);
timer.start();
setPreferredSize(new Dimension(500,500));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Iterates through the Gull Blink images and set the proper image
if(counter >=8){
counter = 0;
timer.stop();
try {
//Randomizes sleep times to make blink look natural
Thread.sleep((long) (Math.random() * 5000));
timer.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
counter++;
}
gull = seagullAnimation[counter].getImage();
g.drawImage(gull,10,-450, this);
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}}
Fixed the Lag. Removed the code that slept the Event Dispatch thread, which seemed to be causing the lag and used the timer to handle the pause between animations.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setGullFrame();
gull = seagullAnimation[counter].getImage();
g.drawImage(gull,10, -450, this);
public void setGullFrame(){
if(counter >=8){
counter = 0;
timer.stop();
timer.setInitialDelay((int) (Math.random() * 5000));
timer.start();
} else {
counter++;
}
}
I want to change the background color of a panel each time repaint() is called. I'm having a hard time doing it with setBackground, so I wonder if a drawRect with the same dimensions as the frame will do the same job, or is this a no-no?
public class Artwork extends JPanel implements Runnable {
boolean running = false;
Random rng = new Random();
public Artwork() {
this.setOpaque(true);
}
public void Start() {
running = true;
Thread thread = new Thread(this);
thread.start();
}
public void Stop() {
running = false;
}
public void run() {
while (running = true) {
repaint();
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
super.setBackground(randomColor());
}
public Color randomColor() {
int r = rng.nextInt(255);
int g = rng.nextInt(255);
int b = rng.nextInt(255);
return new Color(r, g, b);
}
With this the background color changes rapidly regardless of Thread.sleep
With this the background color changes rapidly regardless of Thread.sleep
Painting methods are for painting only!
Don't invoke methods (like setBackground()) that change the property of the component in the paintComponent() method. Swing components automatically repaint() themselves when a property is changed. This will cause an infinite loop as the component repaints itself again and again and again....
The solution is to invoke the setBackground() method in the Thread before invoking the repaint method.
I'm attempting to use a glass pane to gray out a frame while a separate thread performs some image processing (img proc). After the img proc thread finishes, the glass pane should go invisible again. I have confirmed that the glass pane is functioning properly, but repainting doesn't occur before the img proc thread (which indeed executes as expected with the wait and notify working as well) is started. Here's what I have:
The GlassPane class:
class GlassPane extends JComponent implements MouseListener
{
GlassPane()
{
super();
setLayout(new BorderLayout());
setOpaque(false); // So that Color's alpha channel is used
addMouseListener(this);
}
#Override
protected void paintComponent(Graphics g)
{
Rectangle bounds = g.getClipBounds();
g.setColor(new Color(255,255,255,160));
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
...
}
While building the components of the frame:
gPane = new GlassPane();
rootFrame.setGlassPane(gPane);
setGlassPane( false );
...
public void setGlassPane( boolean gray )
{
if( gray )
keyCatcher.disable();
else
keyCatcher.enable();
gPane.setVisible(gray);
gPane.repaint(); // Also tried gPane.repaint(0);
gPane.invalidate();
}
And in the action listener of a button:
...
System.out.println( "Answer button pressed..." );
ctrlr.grayOut();
new Thread( new Runnable()
{
public void run(){
int responses[];
ImgProc ip = new ImgProc(ctrlr);
ArrayList<ColorModel> model = ctrlr.getColorModel();
responses = ip.findResponses( camContent.getCrntImage(), model, (source == ansAndDisplayBtn) );
ctrlr.setResponses(responses);
synchronized(lock)
{
lock.notifyAll();
System.out.println( "Notified..." );
}
}
}).start();
synchronized(lock)
{
try {
System.out.println( "Waiting..." );
lock.wait();
System.out.println( "Responses retreived..." );
} catch (InterruptedException e1) {
e1.printStackTrace();
}
qContent.answer();
qContent.updateResponses();
if( scrnMode )
{
proj_qContent.answer();
proj_qContent.updateResponses();
}
}
ctrlr.showFull();
...
Where ctrlr.grayOut() and ctrlr.showFull() are just:
public void grayOut()
{
((MainUI) mainUI).setGlassPane(true);
}
public void showFull()
{
((MainUI) mainUI).setGlassPane(false);
}
I've read over a lot of this Painting in AWT and Swing and other threads that perform this type of action. It appears to me that I'm doing the same thing as those that are successful...is there something subtle I am missing?
This: lock.wait(); blocks the event dispatch thread so that no drawing can happen. I'd use a SwingWorker for the heavy task. That is, putting the image processing to doInBackground() and the stuff you have after the wait in done().
// Inform the user the task is running
ctrlr.grayOut();
new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
// process the image
...
return null;
}
#Override
protected void done() {
// Everything done, inform the user
...
ctrlr.showFull();
}
}.execute();
I am trying to move a ball in applet using thread but its not moving. Can anyone help me out as m new to applet and proceeding for game development..for reference here is my code
public class ballGame extends JApplet implements Runnable
{
int x_pos=50;
int y_pos=100;
int rad=10;
Thread t;
public void start()
{
super.start();
t=new Thread("t");
t.start();
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.red);
setBackground(Color.BLACK);
g.drawOval(x_pos,y_pos,2*rad,2*rad);
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}//end of paint()
}
Swing is a single thread environment. That is, all updates and interactions are executed within a single thread. Swing is also NOT thread safe. This means that all updates to the UI MUST be executed within the context of that thread (the Event Dispatching Thread or ETD).
Any code that blocks the EDT will prevent it from (amongst other things), repainting the UI and responding to input from the user.
You're paint code will NEVER update the screen, in fact it will make your application appear to "hang", as the paint method isn't being allowed to complete and is blocking the ETD.
It is an exception that the paint method will return quickly after been called and may be called repeatedly in quick succession.
Generally speaking, a Thread is probably a little over kill, something like a javax.swing.Timer would be more then suitable under these circumstances.
public class AnimatedBoat {
public static void main(String[] args) {
new AnimatedBoat();
}
public AnimatedBoat() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int xPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new File("boat.png"));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += direction;
if (xPos + boat.getWidth() > getWidth()) {
xPos = getWidth() - boat.getWidth();
direction *= -1;
} else if (xPos < 0) {
xPos = 0;
direction *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getWidth() * 4, boat.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int y = getHeight() - boat.getHeight();
g.drawImage(boat, xPos, y, this);
}
}
}
As a side note. You should rarely need to override the paint method of a top level container like JApplet or JFrame, while there are a number of good reasons for this, the one that you're going to most interested in is the fact that they're not double buffered, meaning you are likely to see flickering as the screen is updated.
It's better to use something like JPanel and override it's paintComponent method instead.
Take a look at
Performing Custom Painting
Concurrency in Swing
Painting in AWT and Swing
For more information
nb
While I've used a JFrame for my example, it would be a simple matter to take the animation panel and put it into a JApplet, this is another reasons why you don't need/want to extend from top level containers ;)
Having an infinite loop in paint means that not a single pass of the method can complete.
Also you should never call Thread.sleep(100) in the paint method. This blocks the EDT and degrades performance.
Instead use a Swing Timer to do the update and repainting work. Also I would sub-class a JComponent and override paintComponent.
You can not invoke repaint() method inside paint(). And you can not organize infinitely loop inside paint() method - doing so, you are blocking drawing in your applet.
x_posis an int value, thus it is passed to methods by value, not by reference. That is why, when you change its value, the value inside of your circle is not updated...
You create a Thread without a run() method. This method should contain the runnable code... Furthermore, the paint() method is to paint stuff, not update stuff!
So move your while loop from the paint() method into the run() method of your thread:
t=new Thread("t") {
#Override
public void run()
{
while(true)
{
x_pos++;
//validate();
repaint();
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}//end of while
}
};
Note that ballGame does not require the implement Runnable part. As the thread you created will provide it.
Have the while loop inside the run method of Runnable.
UPDATE:
Have this in the start method.
t=new Thread(this);
t.start();
I have a problem with canvas i wanted to show some moving balls on canvas (animation) but there is nothing I can see except black background.
can somebody tell me the mistake in this code and how it will work please.
public CopyOfCleanBallPanel2() throws IOException, InterruptedException {
frame = new JFrame("simple gaming loop in java");
frame.setSize(BOX_WIDTH, BOX_WIDTH);
frame.setResizable(false);
displayCanvas = new CustomCanvas();
displayCanvas.setLocation(0, 0);
displayCanvas.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
displayCanvas.setBackground(Color.BLACK);
displayCanvas.setFont(new Font("Arial", Font.BOLD, 14));
displayCanvas.setPreferredSize(new Dimension(CANVAS_WIDTH,CANVAS_HEIGHT));
frame.add(displayCanvas);
displayCanvas.requestFocus();
frame.setLocationRelativeTo(null);
try {
this.aBall = (BallServer) Naming
.lookup("rmi://localhost/BouncingBalls");
} catch (Exception e) {
System.out.println("Exception: " + e);
}
frame.pack();
frame.setVisible(true);
aBall.start();
startFrameTimer();
}
/*
* Initializes the frame (also game update) timer.
*/
private void startFrameTimer() {
frameTimer.schedule(new FrameTimerTask(), 1, GAME_TIMER_COOLDOWN);
}
public void updateSimulation() throws RemoteException {
repaintCanvas();
}
/*
* This method gets called by the timer. It updates the game simulation and
* redraws it.
*/
private void onFrameTimer() throws RemoteException {
updateSimulation();
}
/*
* Causes the whole canvas to get repainted.
*/
private final void repaintCanvas() throws RemoteException {
Graphics g = displayCanvas.getGraphics();
drawworld(g);
}
private class FrameTimerTask extends TimerTask {
public void run() {
try {
onFrameTimer();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
/*
* This custom canvas overrides the paint method thus allowing for a custom
* painting on the component.
*/
private class CustomCanvas extends Canvas {
#Override
public void paint(Graphics g) {
// Currently the game message gets drawn over the inner border
// of the canvas so we have to repaint the whole thing.
try {
repaintCanvas();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public void drawworld(Graphics g) throws RemoteException {
g.setColor(Color.BLACK);
g.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
System.out.println("i m in drawworld ");
serBall = aBall.getState1(); ***// here it is remote call and there is thread going on suspension***
for (int i = 0; i < currentNumBalls; i++) {
g.setColor(serBall[i].getBallColor(velocity.getLength()));
g
.fillOval((int) (serBall[i].position.getX() - serBall[i]
.getRadius()),
(int) (serBall[i].position.getY() - serBall[i]
.getRadius()), (int) (2 * serBall[i]
.getRadius()), (int) (2 * serBall[i]
.getRadius()));
// Draw our framerate and ball count
g.setColor(Color.WHITE);
g.drawString("FPS: " + currentFrameRate + " Balls: "
+ currentNumBalls, 15, 15);
}
}
P.S: I thought there is some thread problem while I m calling the remote method and rendering the drawworld, either of thread is going on suspension or blocked
Please Help.
jibby lala
When using Swing custom painting is done by overriding the paintComponent() method of a JPanel (or JComponent), not a Canvas. Canvas is an AWT component and should not be used with Swing. See the Swing tutorial on Custom Painting for more information and examples.
Animation should be done by using a Swing Timer so that code is executed on the EDT. The Swing tutorial also has section on "How to Use Swing Timers" and "Concurrency" which helps explain these concepts.
The repaintCanvas() method is unnecessary. To repaint a component you simply invoke repaint() on the component. You should never use the getGraphics() method. All painting methods already receive the Graphics class as a parameter. That is the Grapphics object you should use for painting.
It looks as if you are mixing heavy and light components, which requires some care. Alternatively, you might compare your code to this example.