当前位置: 首页 > 知识库问答 >
问题:

Swing Worker和GUI更新

燕璞
2023-03-14

我是这个社区的新手!

我想问一下SwingWorker及其与GUI的关系。

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

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

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

以下是关于下面发布的代码的一些问题:

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

代码是这样的:

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个答案

邰棋
2023-03-14

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

你怎么称呼它没有错。

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

这是正确的,你描述的情况不会发生<代码>SwingWorker。done()通过延迟的SwingUtilities在EDT上调用。调用调用器调用,而您已经调用了JFrame。在构建SwingWorker(在EDT上)之前,设置可见(true)。

考虑使用对话框,而不是多个帧,如果您试图阻止用户输入,也许是模态对话框(如图所示)。

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

考虑到当前线程的安全性,这当然不是一种更好的方法。如果EDT和Swing工作人员都需要访问这两个成员,请考虑使用<代码> AtomicBoolean <代码>而不是<代码>布尔。

您还应该在某个地方检查interrupted标记,并在更改后退出文件列表循环。

您还可以将任何swing代码包装成SwingUtilities。调用器调用SwingWorker中的任意位置。doInBackground()用于细粒度GUI更新。这样做的效果基本上与调用done()的效果相同,但可以控制调用的时间和次数。查看这里的代码示例。您自己的代码这样做是为了将执行从主线程传递到main()方法中的EDT(此代码模式的原因是所有swing代码都必须在EDT上执行)。

 类似资料:
  • 问题内容: 您好,我想知道从swingworkerthread向jtextarea添加文本的最佳方法是什么,我创建了另一个类,Threadsclass()。execute()调用了jbutton。并且线程与此代码并行运行 现在id要做的是将x的值添加到主gui上的文本区域,任何想法都值得赞赏。 问题答案: JavaDocs有一个很好的例子 看一下发布和处理 潜在的意图是,您仅需要从事件调度线程中更

  • 问题内容: 我对SwingWorker和Java GUI有疑问。 我有几类,其处理的信息,我们可以给他们打电话,和。此处理可能需要很长时间。 这些都是的子类,但是本身并不是直接调用的(这些类使用继承自的方法。为了使EDT自由绘制进度条,在保持对象层次结构时最好的使用方法是什么?是否具有包装器类,并且有其调用?即使不扩展,它仍然可以按我期望的那样工作吗? 编辑:澄清我的问题,即使他们已经是子类,我如

  • 问题内容: 我使用SwingWorker使用Java Swing API制作进度条。 我有一个扩展SwingWorker的类 第二节课(我正在写一篇) 当我在第二个测试器中启动时,在进度条出现之前会显示消息“找不到方法”,而在以后的情况下我希望出现该消息。该怎么办? 问题答案: 将启动一个背景(从中调用该方法),程序将继续执行。 不是阻塞方法,这是使用它的原因,因此您不要阻塞事件调度线程 您可以使

  • 我需要将给定的任何图像转换为字节数组,以满足加密要求。我正在使用JProgressBar监控所选图像较大时的转换进度: 我定义了一个类,它使用,如下所示: 不幸的是,这个错误发生了! 我不知道我的代码出了什么问题!在写这段代码之前,我读了和,但我觉得我遗漏了什么!我能得到一个有用的提示吗。 谢谢:)

  • 问题内容: 我随机地以高频率接收数据对象,并且需要使用这些对象来更新JavaFX GUI。但是,我不想用大量可运行对象填充javafx事件队列(我使用Platform.RunLater)。 我一直在思考如何最好地实现节流算法。 最好有一个单独的GUIUpdater线程来检查例如新对象的阻塞队列,然后在无限循环中例如休眠30ms然后再次检查吗?在这种情况下,阻塞队列是否是最佳数据结构?请注意,我只需

  • 我有一个简单的TKinter GUI,它有一个文本输入框和一个按钮。我想输入文本,点击按钮,让我的程序打印文本。GUI工作正常,除了单击文本输入框并键入时,在调整窗口大小或单击按钮之前,我看不到光标或文本。单击按钮时,文本将显示在输入框中并返回。当我输入文本时,GUI没有更新。我正在OSX10.10上运行Python 3.4。任何想法都欢迎。 下面是代码: