2016-06-10 72 views
0

我是這個社區的新人!Swing Worker和GUI更新

我想問你一些關於SwingWorker及其與GUI的關係。

我知道有關於SwingWorker的一些回答問題,並且我已經閱讀了很多這些問題,並提供了一些有用的建議。

現在我想發佈一些代碼,我寫了一個基本的應用程序,它從指定的目錄中統計文件和文件夾的數量。

由於搜索可能需要很長時間,我希望在此過程中顯示進度條。 此外,我希望用戶有可能通過單擊按鈕或簡單地關閉包含進度欄的框架來停止計數過程。

這裏有在代碼中的一些問題,下面貼出:

  • 調用執行()進行的SwingWorker方法是WaitingFrame構造函數的最後一個指令:有沒有一個更好的地方嗎?
  • WaitingFrame的dispose()方法是從SwingWorker的done()方法調用的,它是正確的嗎? 如果計數過程非常快,可以在等待幀實際可見之前調用dispose方法嗎? 因此,我會有兩個開放的框架...
  • 是否有更好的方法來中斷過程並管理向用戶顯示的消息對話框? 我用了兩個布爾變量,有效和中斷,達到我的目的...

而這裏的代碼:

import java.awt.*; 
import java.awt.event.*; 
import java.io.File; 
import java.io.IOException; 
import javax.swing.*; 
import javax.swing.border.*; 
public class CountFiles 
{ 
    public static void main(String[] args)throws Exception 
    { 
     SwingUtilities.invokeLater(new Runnable(){ 
      public void run(){ 
       try 
       { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        new CountFilesFrame().setVisible(true); 
       } 
       catch(Exception ex){ 
        ex.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 
class CountFilesFrame extends JFrame 
{ 
    private JTextField field; 
    public CountFilesFrame() 
    { 
     super("Conta File e Cartelle"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setResizable(false); 
     JPanel pane=(JPanel)getContentPane(); 
     pane.setBackground(Color.WHITE); 
     pane.setBorder(new EmptyBorder(5,20,5,20)); 
     JPanel center=new StyledPanel(pane,BorderLayout.CENTER,new FlowLayout(FlowLayout.LEFT,5,10)),bottom=new StyledPanel(pane,BorderLayout.SOUTH,new FlowLayout(FlowLayout.LEFT,20,0)); 
     // Center panel 
     center.add(new JLabel("Cartella :")); 
     String text=""; 
     try{ 
      File folder=new File("../"); 
      text=folder.exists()?folder.getCanonicalPath():""; 
     } 
     catch(Exception ex){} 
     field=new JTextField(text,25); 
     center.add(field); 
     // JTextArea 
     String newLine=System.getProperty("line.separator"),message="Scegliere la cartella da cui far partire la ricerca."+newLine+ 
     "Sara' contato il numero di file e di cartelle presenti "+newLine+"nella directory inserita e in tutte le sottocartelle"; 
     JTextArea area=new JTextArea(message); 
     area.setEditable(false); 
     area.setFont(field.getFont()); 
     pane.add(area,BorderLayout.NORTH); 
     // Bottom panel 
     bottom.add(new JButton(new AbstractAction("Cambia Cartella"){ 
      public void actionPerformed(ActionEvent e){ 
       changeDirectory(); 
      } 
     })); 
     bottom.add(new JButton(new AbstractAction("Inizia ricerca"){ 
      public void actionPerformed(ActionEvent e){ 
       new WaitingFrame(CountFilesFrame.this); 
      } 
     })); 
     pack(); 
     setLocationRelativeTo(null); 
    } 
    public void changeDirectory() 
    { 
     JFileChooser chooser=new JFileChooser(field.getText()); 
     chooser.setDialogTitle("Cambia Cartella"); 
     chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 
     if(chooser.showDialog(this,"Scegli")==JFileChooser.APPROVE_OPTION) 
     { 
      try 
      { 
       File selected=chooser.getSelectedFile(); 
       if(selected.exists())field.setText(selected.getCanonicalPath()); 
      } 
      catch(Exception ex){} 
     } 
    } 
    private class WaitingFrame extends JFrame 
    { 
     private Counter counter; 
     public WaitingFrame(CountFilesFrame f) 
     { 
      super("Ricerca File"); 
      setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
      addWindowListener(new WindowAdapter(){ 
       public void windowClosing(WindowEvent e){ 
        stopCounter(); 
       } 
      }); 
      setResizable(false); 
      JPanel pane=(JPanel)getContentPane(),buttonPanel=new StyledPanel(pane,BorderLayout.SOUTH,new FlowLayout(FlowLayout.CENTER,0,10)); 
      JLabel label=new JLabel("Conteggio in corso...",JLabel.CENTER); 
      label.setBorder(new EmptyBorder(0,0,10,0)); 
      pane.add(label,BorderLayout.NORTH); 
      pane.setBackground(Color.WHITE); 
      pane.setBorder(new EmptyBorder(10,40,0,40)); 
      JProgressBar progressBar=new JProgressBar(0,100); 
      progressBar.setBorderPainted(false); 
      progressBar.setIndeterminate(true); 
      pane.add(progressBar,BorderLayout.CENTER); 
      buttonPanel.add(new JButton(new AbstractAction("Annulla"){ 
       public void actionPerformed(ActionEvent e){ 
        stopCounter(); 
       }  
      })); 
      while(pane.getSize().width!=pane.getPreferredSize().width)pack(); 
      setLocationRelativeTo(null); 
      setVisible(true); 
      (counter=new Counter()).execute(); 
     } 
     public void stopCounter() 
     { 
      counter.interrupt(); 
      counter.cancel(true); 
     } 
     private class Counter extends SwingWorker<Void,Void> 
     { 
      private boolean valid=true,interrupted=false; 
      private int filesNumber=0,foldersNumber=0; 
      protected Void doInBackground() 
      { 
       File folder=new File(field.getText()); 
       if(!folder.exists()||!folder.isDirectory())valid=false; 
       else countFiles(folder); 
       return null; 
      } 
      protected void done() 
      { 
       dispose(); 
       if(interrupted)return; 
       else if(!valid)JOptionPane.showMessageDialog(CountFilesFrame.this,"Inserire una cartella valida","Percorso specificato errato",JOptionPane.ERROR_MESSAGE); 
       else JOptionPane.showMessageDialog(CountFilesFrame.this,"Sono stati trovati "+(foldersNumber-1)+" cartelle e "+filesNumber+" file","Ricerca completata",JOptionPane.INFORMATION_MESSAGE); 
      } 
      private void countFiles(File file) 
      { 
       if(file.isDirectory()) 
       { 
        foldersNumber++; 
        for(File nested:file.listFiles())countFiles(nested);    
       } 
       else filesNumber++; 
      } 
      public void interrupt() 
      { 
       interrupted=true; 
      } 
     } 
    } 
} 
class StyledPanel extends JPanel 
{ 
    public StyledPanel(JPanel parent,String position,LayoutManager layout) 
    { 
     super(layout); 
     setBackground(Color.WHITE); 
     parent.add(this,position); 
    } 
} 

我發佈的所有應用程序代碼,所以你可以嘗試編譯運行。

在此先感謝您的幫助! PS:我沒有改變界面語言,我很抱歉。此外,我很抱歉我的英語不好......

+0

*「沒有更改界面語言」*它似乎與問題沒有關係,所以爲什麼你會打擾?我注意到所有的類名和屬性都是英文的。這很方便。 :) –

回答

1

對SwingWorker的execute()方法的調用是WaitingFrame構造函數的最後一條指令:是否有更好的地方呢?

你怎麼稱呼它沒什麼錯。

WaitingFrame的dispose()方法是從SwingWorker的done()方法中調用的,它是正確的嗎?如果計數過程非常快,那麼可以在等待幀實際可見之前調用dispose方法嗎?因此,我會有兩個開放的框架...

這是正確的,你描述的情況不會發生。 SwingWorker.done()EDT上通過延遲呼叫SwingUtilities.invokeLater呼叫,您在構建SwingWorker(在EDT上)之前已呼叫JFrame.setVisible(true)

而不是multiple frames,考慮使用對話框,如果您試圖阻止用戶輸入(如here),可能是模式對話框。

有沒有更好的方法來中斷進程並管理向用戶顯示的消息對話框?我用了兩個布爾變量,有效和中斷,達到我的目的......

當然是有這樣做,考慮到當前的代碼是危險地接近不是線程安全的更好的方法。如果EDT和swing工作人員需要訪問這兩個成員,請考慮使用AtomicBoolean而不是boolean

您還應該檢查某處的interrupted標誌並在其更改後退出您的文件列表循環。

您還可以將任何搖擺代碼包裝到SwingWorker.doInBackground()以內任何地方的SwingUtilities.invokeLater調用中,以獲得細粒度的GUI更新。這樣做基本上具有與調用done()相同的效果,但您可以控制調用的時間和次數。檢查here的代碼示例。你自己的代碼這樣做是爲了在你的main()方法中將執行從主線程傳遞給EDT(這種代碼模式的原因是所有的swing代碼都必須在EDT上執行)。

+0

首先,非常感謝您的建議! – Ansharja

+0

首先,非常感謝您的建議! 我會嘗試應用你說的最後一點。 關於對話框,我已經考慮過使用模態對話框,但是對setVisible的調用不會阻止進程啓動? 在這種情況下,我應該在setVisible()之前調用execute()嗎?我認爲這會對我在第二點提出的問題產生更大的風險...... – Ansharja

+0

'setVisible(true)'之後模態對話框會阻止用戶輸入 - 直到setVisible(false)'調用纔會返回,但它不會阻塞EDT(事件仍然處理)。你必須在setVisible()之前調用'execute()',或者用'doInBackground()'調用它。看看鏈接的雞/蛋問題。它應該解決你的疑惑。 – predi