2011-10-18 107 views
0

我正在編寫一個工具,在文本文件上執行一項任務。該任務需要一些時間才能完成,因此我製作了一個顯示文件名和進度百分比的面板。 用戶可以在一個或多個文件上運行任務,所以我需要爲每個文件顯示一個面板。問題是面板沒有被添加。 我更新我的代碼是包含的建議如下自我:實時向JFrame添加多個JPanel

package sscce.jpanel; 

import javax.swing.JFrame; 
import javax.swing.JTextArea; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.logging.Logger; 
import javax.swing.JButton; 
import javax.swing.BoxLayout; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.SwingConstants; 

public class FProgressDisplay extends JFrame { 
    private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName()); 
    private List<PanelTaskProgress> tasks; 
    JTextArea txtLog; 
    JButton btnAbort; 
    JButton btnClose; 


    public static void main(String[] args) { 
     try { 
      FProgressDisplay frame = new FProgressDisplay(); 
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      frame.setVisible(true); 

      for(int i = 0; i < 10; i++) { 
       frame.addTask(i, "Task"+i); 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
      throw new RuntimeException("Failed to initialize application."); 
     } 
    } 
    /** 
    * Create the frame. 
    */ 
    public FProgressDisplay() { 
     setTitle("Mask tool - Progress"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     getContentPane().setLayout(null); 
     getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 

     JPanel panel = new JPanel(); 
     getContentPane().add(panel); 

     btnAbort = new JButton("Abort"); 
     panel.add(btnAbort); 

     btnClose = new JButton("Close"); 
     panel.add(btnClose); 

     txtLog = new JTextArea(); 
     txtLog.setLineWrap(true); 
     getContentPane().add(txtLog); 

     tasks = new ArrayList<PanelTaskProgress>(); 
    } 

    public void addTask(long id, String fileName) { 
     PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName); 
     tasks.add(newTaskPanel); 
     getContentPane().add(newTaskPanel); 
     validate(); 
     repaint(); 
     LOGGER.info("Added new panel"); 
    } 

    public class PanelTaskProgress extends JPanel { 
     private static final long serialVersionUID = 1L; 
     JLabel lblTaskDescription; 
     JLabel lblProgress; 
     private long id; 
     /** 
     * Create the panel. 
     */ 
     public PanelTaskProgress(long id, String fileName) { 
      try { 
       setLayout(null); 

       lblTaskDescription = new JLabel(id + " " + fileName); 
       //lblTaskDescription.setBounds(10, 11, 632, 14); 
       add(lblTaskDescription); 

       lblProgress = new JLabel("0%"); 
       lblProgress.setHorizontalAlignment(SwingConstants.CENTER); 
       //lblProgress.setBounds(664, 11, 51, 14); 
       add(lblProgress); 

       LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName); 
      } catch (Exception e) { 
       LOGGER.severe("Error creating new panel; " + e.getMessage()); 
      } 
     } 
    } 
} 
+0

1)爲了更好地幫助您,請發佈[SSCCE](http://pscode.org/sscce.html)。 2)不要調用'setBounds()'。這是一個等待中斷的GUI(他們很少等待很久)。 –

+0

SSCCE應該是一個單一的源文件。你爲什麼要堅持使用'setBounds()'? –

+0

好的,我想我現在明白了。順便說一句 - 當刪除setbounds()調用時,幀被最小化。 – Yoav

回答

4

呼叫validate()然後repaint()


這是您的SSCCE的黑客版本。不確定最終的要求是什麼,但我添加了一個按鈕,允許在GUI可見後添加新任務。似乎repaint()調用是不需要的,所以我編輯了它。

import java.awt.event.*; 
import javax.swing.*; 
import java.util.*; 
import java.util.logging.Logger; 

public class FProgressDisplay extends JFrame { 
    private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName()); 
    private List<PanelTaskProgress> tasks; 
    JTextArea txtLog; 
    JButton btnNew; 
    JButton btnAbort; 
    JButton btnClose; 
    static int i; 
    JPanel taskPanel; 

    public static void main(String[] args) { 
     try { 
      FProgressDisplay frame = new FProgressDisplay(); 
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      frame.setVisible(true); 

     } catch (Exception e) { 
      e.printStackTrace(); 
      throw new RuntimeException("Failed to initialize application."); 
     } 
    } 
    /** 
    * Create the frame. 
    */ 
    public FProgressDisplay() { 
     setTitle("Mask tool - Progress"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     // should be done AFTER components are added 
     //pack(); 
     getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 
     taskPanel = new JPanel(); 
     taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS)); 

     JPanel panel = new JPanel(); 
     getContentPane().add(panel); 

     btnNew = new JButton("New"); 
     panel.add(btnNew); 
     btnNew.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent ae) { 
       addTask(++i, "Task " + i); 
      } 
     }); 

     btnAbort = new JButton("Abort"); 
     panel.add(btnAbort); 

     btnClose = new JButton("Close"); 
     panel.add(btnClose); 

     txtLog = new JTextArea(); 
     txtLog.setLineWrap(true); 
     getContentPane().add(txtLog); 

     tasks = new ArrayList<PanelTaskProgress>(); 

     JScrollPane scrollPane = new JScrollPane(taskPanel); 
     getContentPane().add(scrollPane); 

     for(i = 0; i < 10; i++) { 
      addTask(i, "Task"+i); 
     } 
     pack(); 
    } 

    public void addTask(long id, String fileName) { 
     PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName); 
     tasks.add(newTaskPanel); 
     taskPanel.add(newTaskPanel); 
     validate(); 
     //repaint(); 
     LOGGER.info("Added new panel"); 
    } 

    public class PanelTaskProgress extends JPanel { 
     private static final long serialVersionUID = 1L; 
     JLabel lblTaskDescription; 
     JLabel lblProgress; 
     private long id; 
     /** 
     * Create the panel. 
     */ 
     public PanelTaskProgress(long id, String fileName) { 
      try { 
       //setLayout(null); 

       lblTaskDescription = new JLabel(id + " " + fileName); 
       //lblTaskDescription.setPreferredSize(new Dimension(632, 14)); 
       add(lblTaskDescription); 

       lblProgress = new JLabel("0%"); 
       lblProgress.setHorizontalAlignment(SwingConstants.CENTER); 
       //lblProgress.setBounds(664, 11, 51, 14); 
       add(lblProgress); 

       LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName); 
      } catch (Exception e) { 
       LOGGER.severe("Error creating new panel; " + e.getMessage()); 
      } 
     } 
    } 
} 
+1

revalidate()+1 – mKorbel

+0

不起作用。仍然沒有顯示面板。 – Yoav

+0

謝謝。面板現在顯示出來。 – Yoav

1

您可以嘗試從PanelTaskProgress刪除setLayout(null);JPanel默認爲FlowLayout,每個面板都有兩個對齊水平中心的組件。

+0

不起作用。仍然沒有顯示面板。 – Yoav

+0

這很奇怪我試過你用我的修改代碼,我可以看到面板。 –

+0

我會問你的代碼,但上面的解決方案正在工作。不管怎麼說,還是要謝謝你。 – Yoav

1

兩件事情:

首先,因爲你在PanelTaskProgress構造函數中調用setLayout(null);您的面板是空的。改爲撥打setLayout(new FlowLayout());,你會看到他們的內容。

其次,更有趣的是:您的主要方法是在主線程中運行,而不是在事件派發線程中運行。當你在框架上呼叫setVisible()時,EDT開始做事。隨後不久,你開始改變佈局,而不是從EDT。這勢必造成問題。您必須在事件派發線程上創建和修改佈局。

總結你的主要方法

EventQueue.invokeLater(new Runnable() { 
    public void run() { 
     .... 

    } 
}); 

所有Swing程序應該這樣做。