Java中的SwingWorker [关闭]

Posted

技术标签:

【中文标题】Java中的SwingWorker [关闭]【英文标题】:SwingWorker in Java [closed] 【发布时间】:2012-09-20 10:47:12 【问题描述】:

我有问题。

我有一个JFrame。它将创建一个JDialog

JDialog 上的按钮被按下时,它应该被释放并且应该发送一封电子邮件。 同时,我需要另一个JDialog 以不确定的JProgressBar 出现。发送电子邮件时,JDialog 应该被丢弃(并创建一个新的)或者它的内容应该改变。

我已经失败了几个小时,所以我问任何人他(或她)是否愿意给我写一个伪代码来做我想做的事。

只是看看应该在SwingWorker 类中包含什么(或者如果您认为它更好,则使用多线程),何时应该创建/处置JDialog(s),以及在哪里粘贴电子邮件发送...

我知道我在这里要求一个完整的解决方案,但我已经陷入困境并且已经失败了很多次......这是我最后的手段......

【问题讨论】:

查看this answer 以了解您需要调整doInBackGround 以发送电子邮件的示例 你最后的手段永远不应该是要求 *** 读者为你编写代码。发布可以以正确问答格式回答的具体问题。或聘请合同程序员 -1 并投票以离题结束(这不是问题,而是其他人已经指出的工作请求) 您应该花时间阅读Concurrency in Swing 课程,这样可以减轻您的压力 【参考方案1】:

我为您做了一个简短的示例,希望对您有所帮助。基本上显示了一个带有按钮的JFrame

当点击框架上的JButton 时,将出现一个JDialog 和另一个JButton发送电子邮件) - 这将代表电子邮件对话框

当按下emailDialog 上的JButton 时,它会处理emailDialog 并创建一个新的JDialog 来保存进度条(或者在这种情况下是一个简单的@987654333 @):

然后它创建并执行SwingWorker 以发送电子邮件,并在完成后显示JDialogdispose() 并显示发送成功的JOptionPane 消息:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class Test 

    public static void main(String[] args) throws Exception 
        SwingUtilities.invokeLater(new Runnable() 

            @Override
            public void run() 
                new Test().createAndShowUI();
            
        );
    

    private void createAndShowUI() 
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initComponents(frame);
        frame.setPreferredSize(new Dimension(300, 300));//testing purposes
        frame.pack();
        frame.setVisible(true);
    

    private void initComponents(final JFrame frame) 

        final JDialog emailDialog = new JDialog(frame);
        emailDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        emailDialog.setLayout(new BorderLayout());

        JButton sendMailBtn = new JButton("Send Email");
        sendMailBtn.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                //get content needed for email from old dialog

                //get rid of old dialog
                emailDialog.dispose();

                //create new dialog
                final JDialog emailProgressDialog = new JDialog(frame);
                emailProgressDialog.add(new JLabel("Mail in progress"));
                emailProgressDialog.pack();
                emailProgressDialog.setVisible(true);

                new Worker(emailProgressDialog).execute();

            
        );

        emailDialog.add(sendMailBtn, BorderLayout.SOUTH);
        emailDialog.pack();

        JButton openDialog = new JButton("Open emailDialog");
        openDialog.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                emailDialog.setVisible(true);
            
        );

        frame.getContentPane().add(openDialog);

    


class Worker extends SwingWorker<String, Object> 

    private final JDialog dialog;

    Worker(JDialog dialog) 
        this.dialog = dialog;
    

    @Override
    protected String doInBackground() throws Exception 

        Thread.sleep(2000);//simulate email sending

        return "DONE";
    

    @Override
    protected void done() 
        super.done();
        dialog.dispose();
        JOptionPane.showMessageDialog(dialog.getOwner(), "Message sent", "Success", JOptionPane.INFORMATION_MESSAGE);

    

【讨论】:

你应该为我的公司工作,你看起来很便宜! ;-) 可能很便宜,但代码不正确。 doInBackground 不会在 EDT 上调用,因此它不应调用 JOptionPane.showMessageDialogdialog.dispose 如果 doInBackground 会在 EDT 上运行,为什么还要费心创建一个 SwingWorker ... doInBackground 在工作线程上运行,无论你在哪里构造或执行SwingWorker(这是一件好事)。看看execute方法的源码就知道了 我从不建议不要使用SwingWorker。您使用SwingWorker,但在doInBackground 方法中根本不执行任何与Swing 相关的操作。我在问题下的第一条评论中链接到一个示例 @DavidKroukamp 只需覆盖 SwingWorker 中的方法 done() 并将调用移至该方法中的 JOptionPane.showMessageDialog(frame, "Message sent", "Success", JOptionPane.INFORMATION_MESSAGE);。一旦 doInBackground() 完成并在 EDT 上运行,就会调用方法 done()【参考方案2】:

@大卫·克鲁坎普

来自 Substance L&F 的输出(您对用于测试目的的 EDT 有任何不确定性)

run:
JButton openDialog >>> Is there EDT ??? == true
Worker started >>> Is there EDT ??? == false
waiting 30seconds 
Worker endeded >>> Is there EDT ??? == false
before JOptionPane >>> Is there EDT ??? == false
org.pushingpixels.substance.api.UiThreadingViolationException: 
     Component creation must be done on Event Dispatch Thread

还有另外 200 行关于细节的内容

输出是"correct container created out of EDT"

我将在另一个 L&F 上进行测试,Nimbus 可能存在问题,SystemLokkAndFeel 在大多数情况下并不关心 EDT 上的大错误(对 EDT 的敏感性非常不同),Metal 默认情况下没有任何问题Windows 平台和 Java6,那么您的示例也适用于第二个基础

编辑

Nimbus 也不在乎

来自代码

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;

public class Test 

    public static void main(String[] args) throws Exception 
        try 
            for (UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) 
                if ("Nimbus".equals(info.getName())) 
                    UIManager.setLookAndFeel(info.getClassName());
                    UIManager.getLookAndFeelDefaults().put("nimbusOrange", (new Color(127, 255, 191)));

                    break;
                
            
         catch (ClassNotFoundException ex) 
         catch (InstantiationException ex) 
         catch (IllegalAccessException ex) 
         catch (javax.swing.UnsupportedLookAndFeelException ex) 
        
        SwingUtilities.invokeLater(new Runnable() 

            @Override
            public void run() 
                /*try 
                    UIManager.setLookAndFeel(
                            "org.pushingpixels.substance.api.skin.SubstanceOfficeBlue2007LookAndFeel");
                    UIManager.getDefaults().put("Button.font", new FontUIResource(new Font("SansSerif", Font.BOLD, 24)));
                    UIManager.put("ComboBox.foreground", Color.green);
                 catch (Exception e) 
                */
                new Test().createAndShowUI();
            
        );
    

    private void createAndShowUI() 
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initComponents(frame);
        frame.setPreferredSize(new Dimension(300, 300));//testing purposes
        frame.pack();
        frame.setVisible(true);
    

    private void initComponents(final JFrame frame) 

        final JDialog emailDialog = new JDialog(frame);
        emailDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        emailDialog.setLayout(new BorderLayout());
        JButton sendMailBtn = new JButton("Send Email");
        sendMailBtn.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                //get content needed for email from old dialog
                //get rid of old dialog
                emailDialog.dispose();
                //create new dialog
                final JDialog emailProgressDialog = new JDialog(frame);
                emailProgressDialog.add(new JLabel("Mail in progress"));
                emailProgressDialog.pack();
                emailProgressDialog.setVisible(true);
                new Worker(emailProgressDialog, frame).execute();

            
        );
        emailDialog.add(sendMailBtn, BorderLayout.SOUTH);
        emailDialog.pack();
        JButton openDialog = new JButton("Open emailDialog");
        openDialog.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                System.out.println("JButton openDialog >>> Is there EDT ??? == " + SwingUtilities.isEventDispatchThread());
                emailDialog.setVisible(true);
            
        );
        frame.getContentPane().add(openDialog);
    


class Worker extends SwingWorker<String, Object> 

    private final JDialog dialog;
    private final JFrame frame;

    Worker(JDialog dialog, JFrame frame) 
        this.dialog = dialog;
        this.frame = frame;
    

    @Override
    protected String doInBackground() throws Exception 
        System.out.println("Worker started >>> Is there EDT ??? == " + SwingUtilities.isEventDispatchThread());
        System.out.println("waiting 30seconds ");
        Thread.sleep(30000);//simulate email sending
        System.out.println("Worker endeded >>> Is there EDT ??? == " + SwingUtilities.isEventDispatchThread());
        dialog.dispose();
        System.out.println("before JOptionPane >>> Is there EDT ??? == " + SwingUtilities.isEventDispatchThread());
        JOptionPane.showMessageDialog(frame, "Message sent", "Success", JOptionPane.INFORMATION_MESSAGE);
        System.out.println("before JOptionPane >>> Is there EDT ??? == " + SwingUtilities.isEventDispatchThread());
        return null;
    

【讨论】:

+1 谢谢我知道我哪里出错了。根据@GuillaumePolet 答案更新代码

以上是关于Java中的SwingWorker [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

java - JLabel setForeground 在 SwingWorker 中不起作用

Java - 如何将 JProgressBar 与 SwingWorker 一起使用

java遇到的问题及解答

java swingworker线程更新main Gui

如果使用 SwingWorker 加载数据,何时将 TabelModel 绑定到 JTable?

发布/处理使 SwingWorker 变慢