Nick Johnson
Nick Johnson

Reputation: 167

Image not drawing after sleep java

I am trying to have a background image draw then have a character draw over it. My code was working until I added sleep do I didn't get 1500 fps.

package sylvyrfysh.screen;

import javax.swing.*;
import java.awt.*;
import game.infos.Information;

public class ImageLoadDraw extends JFrame{
/**
 * 
 */
private static final long serialVersionUID = 1L;
public static void main(){
    DisplayMode dm=new DisplayMode(Information.sX,Information.sY,16,DisplayMode.REFRESH_RATE_UNKNOWN);
    ImageLoadDraw i = new ImageLoadDraw();
    i.run(dm);
}
public void run(DisplayMode dm){
    setBackground(Color.PINK);
    setForeground(Color.WHITE);
    setFont(new Font("Arial",Font.PLAIN,24));
    s=new Screen();
    try{
        loadpics();
        s.setFullScreen(dm,this);
        try{
            Thread.sleep(10000);
        }finally{
            doRun=false;
            s.restoreScreen();
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}
private void loadpics() {
    bg=new ImageIcon("src/sylvyrfysh/screen/maze_icon.png").getImage();
    chara=new ImageIcon("src/sylvyrfysh/screen/char.png").getImage();
    repaint();
}
public void paint(Graphics g){
    if(g instanceof Graphics2D){
        Graphics2D g2=(Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    }
    while(true&&doRun){
        g.drawImage(bg,0,0,null);
        g.drawImage(bg,0,480,null);
        g.drawImage(bg,360,0,null);
        g.drawImage(bg,360,480,null);
        g.drawImage(bg,720,0,null);
        g.drawImage(bg,720,480,null);
        g.drawImage(chara,imgX,imgY,null);
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
private Screen s;
public static int imgX=0;
private int imgY=525;
private Image bg,chara;
private Boolean doRun=true;
}

Any ideas on what is causing it and how to fix it? Like I said, with no sleep it works fine.

Upvotes: 1

Views: 1194

Answers (3)

MadProgrammer
MadProgrammer

Reputation: 347194

Swing is an single threaded framework. That is all UI interactions and modifications are expected to be executed within the content of the Event Dispatching Thread, including repaint requests.

Anything that stops, blocks or otherwise prevents this thread from running will prevent the EDT from processing new events, including repaint requests. This will, essentially, make it appear that you program has hung (or stopped responding), because it has.

In your run method you are calling Thread.sleep. This is likely stopping the EDT from processing new events, but because you've actually called the method from the "main" thread, it might actually work, however...

In you paint method, you have an infinite loop AND a Thread.sleep call. These WILL stop the EDT from running, as paint is called from within the context of the EDT.

Painting won't always occur immediately, on some systems, until the paint method returns, it may not be pushed to the device for output, so, even the idea of looping within the paint, regardless of the fact that it will cause problems for the EDT, is a bad idea any way.

Unlike some other UI frameworks, you do not need to implement a "main-loop", Swing takes care of this for you.

Instead, in your paint method, you should simply paint what you need to paint for that cycle and exit.

Instead, you should do something like...

public void paint(Graphics g){
    // Painting is a complex series of chained methods, failing to call super.paint
    // to cause significant issues
    super.paint(g);
    // Graphics is guaranteed to be an instance of Graphics2D since I think 1.4
    // You should create a copy, so any changes you make are not carried onto the
    // next component, Graphics is shared between all the components being painted
    // in this paint cycle.
    Graphics2D g2=(Graphics2D)g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g2.drawImage(bg,0,0,null);
    g2.drawImage(bg,0,480,null);
    g2.drawImage(bg,360,0,null);
    g2.drawImage(bg,360,480,null);
    g2.drawImage(bg,720,0,null);
    g2.drawImage(bg,720,480,null);
    g2.drawImage(chara,imgX,imgY,null);
    // If you create, you should dispose of it...
    g2.dispose();
}

...instead

Instead of Thread.sleep you should be making use of something like javax.swing.Timer, for example...

s=new Screen();
try{
    loadpics();
    s.setFullScreen(dm,this);
    Timer timer = new Timer(10000, new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            s.restoreScreen();
        }
    });
    timer.setRepeats(false);
    timer.start();
}catch(Exception e){
    e.printStackTrace();
}

Take a look at Concurrency in Swing for more details.

You should also avoid overriding top level containers and especially overriding paint. Painting a complex series of chained method calls, each one performing a particular job, building up on top of each other to produce a final result.

Instead, you should start with a custom component of some kind, extending from JPanel for example, and override it's paintComponent method, making sure you call super.paintComponent before you do any of you own painting.

Take a look at Performing Custom Painting for more details

Upvotes: 1

user2511414
user2511414

Reputation:

I THINK->This is because you need to call the loadpics() parallel, try this

public void run(DisplayMode dm){
    setBackground(Color.PINK);
    setForeground(Color.WHITE);
    setFont(new Font("Arial",Font.PLAIN,24));
    s=new Screen();
        loadpics();
        s.setFullScreen(dm,this);
        try{
            new Thread(new Runnable() {
      @Override
      public void run() {try {Thread.sleep(1000);doRun=false;s.restoreScreen();} catch (Exception e) {}
      }
    }).start();
}

also setting the doRun as volatile. private Boolean doRun=true;

Upvotes: 0

libik
libik

Reputation: 23029

Well this one Thread.sleep(10000); turn off EVERYTHING for 10 seconds. This is NOT what you want. Even doing it for 30 milisec (which is ~30frames/sec) is not what you want, because it stops even input etc.

You should use Timer. It runs timing in another thread and it sleeps and wake up only that thread automatically for given number of milisec, so it does not affect your program and it can call it only after 30milisec for example.

Still to have good application, this timer should have low value and you should count how long passed through System.nanoTime() and for example repaint once each 30milisec, however read input each 5milisec etc.

Upvotes: 0

Related Questions