Reputation: 167
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
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
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
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