2016-09-14 69 views
3

要在这里解释一下我的问题是MCVE这里一下[点击JButtonJDialog A打开JDialog B:漫长的过程:意外延迟

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.FlowLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JDialog; 

public class DiagA extends JDialog { 

    private DiagB diag; 

    public DiagA() { 

     super(); 
     setTitle("main diag"); 
     setSize(200, 150); 
     setLocation(400,400); 

     JButton btn = new JButton("Show DiagB"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 

       showDiag(); 
      } 
     }); 
     add(btn, BorderLayout.NORTH); 

     //make main frame visible 
     setVisible(true); 
    } 

    void showDiag() { 

     if(diag == null) { 

      diag = new DiagB(); 

      //this prints out as expected 
      System.out.println("set visible done"); 

      try { 
       Thread.sleep(3000); 
      } catch (InterruptedException ex) {} 

      //only after the delay diag shows in full 
     } 
    } 

    public static void main(String[] args) { 
     new DiagA(); 
    } 
} 

class DiagB extends JDialog { 

    public DiagB() { 

     super(); 
     setTitle("2nd diag"); 
     setSize(150, 100); 
     setLocation(600,420); 
     setLayout(new FlowLayout(FlowLayout.CENTER)); 
     getContentPane().setBackground(Color.YELLOW); 
     setVisible(true); 
    } 
} 

正如你可以在代码中看到我添加了一个3秒延迟创建后DiagB。 点击该按钮DiagB这样表示:

enter image description here

的3秒延时结束后唯一,DiagB显示全:

enter image description here

我的问题是:
一个。为什么DiagB在构建后没有完全显示? (仅当showDiag()返回时才显示全部)。 b。我的问题的原因是DiagB需要更新,在DiagA长进程。
什么是更新的正确方法?是否需要在每个更新过程中使用SwingWorker

+1

如果它是显示而不是用户交互,它不应该是一个'JDialog'这是,嗯,与用户对话。在事件处理程序中,应该永远不会进行睡眠(或任何其他长操作)。 – RealSkeptic

+1

@RealSkeptic我明白你说的关于事件处理程序长时间操作的。('JDialog'或'JFrame'不会让这种情况下太大的差别。一个'可能需要JDialog'对于形态为例)。 – c0der

+1

模态意味着用户交互是立即需要的。否则,它的使用不正确。 – RealSkeptic

回答

4

一个。 showDiag在GUI线程上运行。当GUI线程休眠时,GUI将完全死亡。

b。是的,使用SwingWorker对于长时间运行的任务和使用SwingUtilities.invokeLater()提交GUI的更新任务回到GUI线程。或者,实现SwingWorker#done()这是在SwingWorker任务完成后在GUI线程上运行的便捷方法。

+0

谢谢。我明白你的意思,“稍后安排行动”。在每个更新过程中使用“SwingWorker”都很麻烦。我宁愿在更新的('DiagB')对象中实现它。有什么建议? – c0der

+1

@MarkoTopolnik注意OP使用的睡眠*** ***模拟长时间运行的任务,所以他们一**'SwingWorker'的建议**向下靠近帖子底部似乎是最好的策略这一点。 –

+2

@AndrewThompson对,我更新推荐'SwingWorker' +'invokeLater'。 –

0

基于马尔科Topolnik答案,安德鲁·汤普森评论,我扭曲了SwingWorker漫长的过程。
这工作得很好:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.FlowLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.SwingWorker; 

public class DiagA extends JDialog { 

    private FrameB frame; 
    private JButton btn; 

    public DiagA() { 

     super(); 
     setTitle("main frame"); 
     setSize(200, 150); 
     setLocation(400,400); 

     btn = new JButton("Show Frame B"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 

       show2ndFrame(); 
      } 
     }); 
     add(btn, BorderLayout.NORTH); 
     setVisible(true); 
    } 

    void show2ndFrame() { 

     if(frame == null) { 

      frame = new FrameB(); 
      btn.setText("Exit"); 

     }else { 

      System.exit(0); 
     } 

     doWork(); 
    } 

    private void doWork() { 

     SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() { 

      @Override 
      protected Void doInBackground() throws Exception { 

       try { 

        for(int i = 1 ; i<=100 ; i++) { 
         //represents a long process 
         Thread.sleep(100); 
         frame.update(i); 
        } 

       } catch (InterruptedException ex) {} 
       return null; 
      } 
     }; 
     sw.execute(); 
    } 

    public static void main(String[] args) { 
     new DiagA(); 
    } 
} 

class FrameB extends JFrame { 

    JLabel label; 

    public FrameB() { 

     super(); 
     setTitle("2nd frame"); 
     setSize(150, 100); 
     setLocation(600,420); 
     setLayout(new FlowLayout(FlowLayout.CENTER)); 
     getContentPane().setBackground(Color.YELLOW); 
     label = new JLabel("0"); 
     add(label); 
     setVisible(true); 
    } 

    void update(int progress) { 

     label.setText(String.valueOf(progress)); 
    } 
}