2012-08-11 31 views
2

我试图创建一个游戏,我开始加载屏幕,它将加载所有需要的文件。我想显示完成的百分比,但它不起作用。 JPanel只在Loading_files完成后加载repaint()。我不知道什么是错的。Java JFrame - 没有重画()直到完成另一个线程

Main.java

package Main; 

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Toolkit; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class Main extends JFrame{ 

//-------------- Final Variables -------------- 
//Screen Related 
public final static int JFRAME_WIDTH = 800; 
public final static int JFRAME_HEIGHT = 600; 
public final static Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize(); 
public final static int SCREEN_WIDTH = SCREEN_SIZE.width; 
public final static int SCREEN_HEIGHT = SCREEN_SIZE.height; 
//Game Related 
public final static String NAME = "Xubris"; 
public final static String IMAGE_DIRECTORY = System.getProperty("user.dir") + "\\images\\"; 
public static final int FPS = 1000/36; 

//-------------- Dynamic Variables -------------- 
//Global 
public static JFrame main; 

public static void main(String[] args) { 
    //Start the Loading screen 
    Loading load = new Loading(); 

    main = new JFrame(NAME); 

    main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    main.setSize(JFRAME_WIDTH, JFRAME_HEIGHT); 
    main.setLocation((SCREEN_WIDTH-JFRAME_WIDTH)/2, (SCREEN_HEIGHT-JFRAME_HEIGHT)/2); 

    //Add Content 
    main.getContentPane().add(load); 

    main.setResizable(false); 
    main.setUndecorated(false); 
    main.setVisible(true); 
} 

} 

Loading.java

package Main; 

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 
import javax.swing.JPanel; 

public class Loading extends JPanel implements Runnable{ 

//Pictures 
BufferedImage background; 

//-------------- Final Variables -------------- 
private final int num_of_files = 32; 

//-------------- Dynamic Variables -------------- 
//Global Variables 
private double loading_percentage = 0; 
private int num_of_loaded_files = 0; 

public Loading(){ 
    try { 
     background = ImageIO.read(new File(Main.IMAGE_DIRECTORY + "Background_Loading.jpg")); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    //Start the thread 
    new Thread(new LoadingFiles()).start(); 
    new Thread(this).start(); 
} 

public void paint(Graphics g){ 
    g.drawImage(background, 0, 0, this); 
    for(int i = 0; i < loading_percentage; i=i+15){ 
     g.setColor(new Color(20,241,47)); 
     g.drawRect(180 + (i/15)*(50+10), 375, 50, 50); 
    } 
} 

@Override 
public void run(){ 
    while(true){ 
     repaint(); 
    } 
} 

class LoadingFiles implements Runnable{ 
    public void run() { 
     try { 
      Thread.sleep(100); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     num_of_loaded_files++; 
     loading_percentage = (num_of_loaded_files/num_of_files)*100; 

     if(num_of_loaded_files!=32) 
      run(); 
    } 

} 
} 
+3

在制作[开机画面]看看(http://stackoverflow.com/questions/9997509/designing-a-splash-screen-java)in java。 'while(true)repaint();'可能是一个坏主意,也... – 2012-08-11 23:55:48

+3

另外,'paint()'中的循环将会阻止你重画多次。您需要以其他方式重新调度重新计划 - 例如,使用'SwingUtilities.invokeLater()'。 – 2012-08-12 00:00:03

+3

不要阻塞EDT(Event Dispatch Thread) - 当发生这种情况时GUI将“冻结”。而不是调用'Thread.sleep(n)'实现一个Swing'Timer'来重复执行任务,或者一个'SwingWorker'执行长时间运行的任务。有关更多详细信息,请参见[Swing中的并发](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 – 2012-08-12 02:18:05

回答

7

阻断EDT和重绘聚结在我的第一个想法,以及(这就是为什么我upvoted的评论)。但有好奇心的人 - 无论是:-)

  • 它是完全有效的调用从任何线程重绘(虽然在紧密while循环这样做肯定会减慢UI反应)
  • 不重画真正的问题如预期的那样,甚至在一些清理之后(见下文)。造成这种情况的罪魁祸首是纯粹的算术

以下行:

loading_percentage = (num_of_loaded_files/num_of_files)*100; 

是0,直到

num_of_loaded_files == num_of_files 

是,直到一切都加载。我们都犯了过早下结论:-)

一些清理工作:

  • 以下Java命名约定使得代码更易于阅读
  • 没有覆盖的油漆,而不是重写paintComponent
  • 随时拨打超级在paintComponent中(默认情况下JPanel的报告是不透明的,也就是必须填写它的区域
  • 不需要交织线程,只需让加载线程在加载后调用repaint ED下一图像
  • 得到算术正确:-)

代码:

public class Loading extends JPanel { 

    // Pictures 
    private BufferedImage background; 

    // -------------- Final Variables -------------- 
    private final int numOfFiles = 32; 

    // -------------- Dynamic Variables -------------- 
    // Global Variables 
    private double loadingPercentage = 0; 

    private int numOfLoadedFiles = 0; 

    public Loading() { 
     background = XTestUtils.loadDefaultImage("moon.jpg"); 
     // Start the thread 
     new Thread(new LoadingFiles()).start(); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.drawImage(background, 0, 0, this); 
     for (int i = 0; i < loadingPercentage; i = i + 15) { 
      g.setColor(new Color(20, 241, 47)); 
      g.drawRect(180 + (i/15) * (50 + 10), 375, 50, 50); 
     } 
    } 

    class LoadingFiles implements Runnable { 
     @Override 
     public void run() { 

      while (numOfLoadedFiles < 32) { 
       numOfLoadedFiles++; 
       loadingPercentage = (double) numOfLoadedFiles/numOfFiles 
         * 100; 
       repaint(); 
       try { 
        // simulate the loading 
        Thread.sleep(200); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

    } 

    public static void main(String[] args) { 
     JFrame frame = new JXFrame("", true); 
     frame.add(new Loading()); 
     frame.setSize(600, 600); 
     frame.setVisible(true); 
    } 
} 
+0

总是有兴趣阅读你的答案和学习一切都来自:-)但是,在某些情况下,如'paintComponent(...)'方法内部,如果用'g.fillRect(x,h,size,size)'写一个for循环,那么大多数情况下能够看到第一个和最后一个Rectangle,在循环之间创建的Rectangle可能会丢失。你是对的,可能是在某些情况下,实际的东西需要一点时间来调用repaint(),它肯定可以工作。但是在OP的线程中,'run()'方法只在'while循环'中调用了'repaint()'调用。 – 2012-08-12 09:49:44

+0

这就是我担心的真正原因:-) – 2012-08-12 09:50:03

+0

这是与此问题相关的[线程](http://stackoverflow.com/q/10338163/1057230) – 2012-08-12 10:08:13

相关问题