忽略事件派发线程如何让这个程序工作?

时间:2015-05-08 19:28:11

标签: java event-dispatch-thread invokelater

我试图看看我是否可以回答this question earlier today。我意识到我并不完全理解Event Dispatch Thread EDT )。 Googling确认并帮助了这一点并澄清了why I don't。 (This也可能与理解有关。)

代码设置GUI,稍后(如前面的问题中所述)更新文本字段,直到取消设置标志。

我有几个问题/要求。

  • 如果两个调用(swingInitdoIt)都在invokeLater块之外(如图所示),请解释为什么以下代码运行正常,因为这两个调用都会影响或查询GUI但是它们都没有在EDT上执行(是吗?)。这不是故障吗?

  • 如果swingInit的电话位于doIt内且invokeLater位于swingInit之外,则代码也会运行。所以doIt在EDT上执行,但不应该在EDT上执行doIt是个问题吗? (我很惊讶这有效。我应该去过吗?)

  • 我想我理解为什么invokeLater位于swingInit内,无论invokeLater位于何处,它都会挂起:doIt的目的只是初始化 GUI(对吧?)。

  • 只应在EDT上启动invokeLater(可能来自发生的事件),但import static java.awt.EventQueue.invokeLater; import java.awt.event.*; import javax.swing.*; public class Whatever { static boolean flag = true; static JTextField tf = new JTextField("Hi",20); static JPanel p = new JPanel(); static JFrame f = new JFrame(); static JButton b = new JButton("End"); public static void main(String[] args) { swingInit(); invokeLater ( new Runnable() { @Override public void run() { // swingInit(); // doIt(); } } ); doIt(); } static void swingInit() { b.addMouseListener ( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { flag = false; JOptionPane.showMessageDialog(null,"Clicked... exiting"); System.exit(0); } } ); p.add(tf); p.add(b); f.add(p); f.setVisible(true); f.pack(); f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } static String getInfo(){ return "Hello... " + Math.random(); } static void doIt(){ while(flag) tf.setText(getInfo()); }; } 阻止

  • >

(EDT概念的历史很有意思。并非总是如此。请参阅上面的链接"为什么我不理解它。)

 <android>
   <manifestAdditions><![CDATA[
      <manifest android:installLocation="auto">
         <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="19" />
         <uses-permission android:name="android.permission.INTERNET"/>
         <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
         <application>
            <!-- this meta-data tag is required for AdMob  -->
            <meta-data android:name="com.google.android.gms.version" android:value="4452000"/>
            <!-- this activity is required for AdMob -->
            <activity android:name="com.google.android.gms.ads.AdActivity"
             android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
             android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
         </application>
      </manifest>
   ]]></manifestAdditions>
 </android>

2 个答案:

答案 0 :(得分:3)

获取每个要点:

  • 代码在主线程上启动 - EDT并行运行。 构建后面的UI后,swingInit返回 控制EDT,允许dotIt在主线程上并行执行

  • 与上述类似的情况,但在此您要保证在EDT上构建UI(按照Oracle的建议)。

  • 长时间运行的任务被放置在EDT上,阻止它显示(如果放在swingIt之前)或绘画和交互(如果放在后面)。 the purpose of invokeLater is ONLY to initialize the GUI目的是将非线程安全的Swing调用放到EDT上。如果在主要方法中,我建议使用SwingUtilities.invokeAndWait

  • 如果您希望像这样更新用户界面,请考虑使用SwingTimer进行更新。

在EDT 之外运行EDT特定的非线程安全代码并不能保证失败,但它会邀请失败(当两个(或更多)线程发生冲突时)尝试同时更新数据)。

我曾经花了几个小时追踪一个神秘的NullPointerException,但却意识到这是一个LookAndFeel问题,其电话不在美国东部时间。学过的知识。

答案 1 :(得分:2)

static void doIt(){
  while(flag)     
    tf.setText(getInfo());
}; 

doIt内的忙循环占用GUI线程(在该循环中旋转),这将导致GUI挂起。

你没有真正解释你的意思&#34;运行得很好&#34;但是我认为这是你所看到的问题。

您可能希望使用Swing Timer来执行类似循环中所做的操作。