Swing Worker和GUI更新

时间:2016-06-10 11:26:46

标签: java swing interface swingworker

我是这个社区的新手!

我想问你一些关于SwingWorker及其与GUI的关系。

我知道有一些关于SwingWorker的问题,我已经阅读了很多,并提出了一些有用的建议。

现在我想发布一些我为基本应用程序编写的代码,它会计算指定目录中的文件和文件夹数量。

由于搜索可能需要花费大量时间,因此我希望在此过程中显示进度条。 此外,我希望用户可以通过单击按钮或只是关闭包含进度条的框架来停止计数过程。

以下代码中有一些问题:

  • 对SwingWorker的execute()方法的调用是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:我没有改变界面语言,对不起。另外,我很抱歉我的英语不好......

1 个答案:

答案 0 :(得分:1)

  

对SwingWorker的execute()方法的调用是WaitingFrame构造函数的最后一条指令:它有更好的地方吗?

你如何称呼它并没有错。

  

WaitingFrame的dispose()方法是从SwingWorker的done()方法调用的,是否正确?如果计数过程非常快,可以在等待帧实际可见之前调用dispose方法吗?结果,我会有两个开放框架......

这是正确的,你描述的情况不可能发生。 JFrame.setVisible(true)通过延迟EDT来电呼叫SwingWorker,您在构建boolean(在EDT上)之前已经呼叫interrupted

如果您试图阻止用户输入(例如SwingUtilities.invokeLater),请考虑使用对话框,而不是multiple frames

  

是否有更好的方法来中断流程并管理向用户显示的消息对话框?我使用了两个布尔变量,有效和中断,以达到我的目的......

考虑到您当前的代码危险地接近于不是线程安全的,确实有一种更好的方法。如果EDT和swing工作人员都需要访问这两个成员,请考虑使用here而不是SwingUtilities.invokeLater

您还应该在某处检查SwingWorker.doInBackground()标志,并在更改后退出文件列表循环。

您还可以将任何swing代码包装到done() main()内的success: function(response) { if (response.success == true) { // if success we would show message // and also remove the error class $('#the-message').append('<div class="alert alert-success">' + '<span class="glyphicon glyphicon-ok"></span>' + ' Data has been saved' + '</div>'); $('.form-group').removeClass('has-error') .removeClass('has-success'); $('.text-danger').remove(); //perform redirect window.location = "Your desired url"; } 调用中,以进行细粒度的GUI更新。这样做基本上具有与调用<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> 时相同的效果,但您可以控制调用它的次数和次数。检查AtomicBoolean以获取代码示例。您自己的代码执行此操作以将执行从主线程传递到您在 <!--appear when room to display is smaller--> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#top"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Your Logo</a> </div> <div class="collapse navbar-collapse" id="top"> <ul class="nav navbar-nav"> <li class="active"> <a href ="put your link here"> Item </a> </li> <!--align content to the right--> <ul class="nav navbar-nav navbar-right"> <li class="active"> <a href =""> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>&nbsp; Item </a> </li> <li class="active"> <a href =""> <span class="glyphicon glyphicon-off" aria-hidden="true"></span>&nbsp; Item </a> </li> </ul> </div> </div> </nav> 方法内的EDT(此代码模式的原因是所有swing代码必须在EDT上执行)。