2012-08-11 30 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

相關問題