2016-06-10 76 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