2016-06-17 18 views
11

Zaten Event Dispatch thread'un nasıl çalıştığını biliyorum. Aşağıdaki gibi Olay Gönderme iş parçacığında kısa ve uzun olaylar varsa, uygulama yanıt veremez. Swing yanıt Uğruna Bir olay, Event Dispatch Thread kuyruğunun başlangıcına nasıl eklenir?

enter image description here

, Olay Sevk iplik sadece kısa etkinlikler için kullanılmalıdır. uzun olaylar SwingWorkers üzerinde yürütülmelidir.

enter image description here

kısa olayların bir sürü olduğunu düşünün.

enter image description here Olaylar Olay Gönderme iş parçacığı içinde yürütülmelidir ve Olay Sevk İpliği sırasındaki diğer olaylardan önce yürütmek istediğiniz özel bir olayınız vardır. Ancak, olaylar varsayılan olarak sıranın sonuna kadar sıralanır ve hatta InvokeLater aynı şeyi yapar.

Etkinlik Olay İleti Başlığı'nın başına bir olayı yerleştirmek için herhangi bir çözüm var mı?

+1

[Bu] 'nın olası kopyası (http://stackoverflow.com/q/37841987/230513). Birden çok "SwingWorker" örneğini [bu] gibi senkronize edin (http://stackoverflow.com/a/11372932/230513). – trashgod

+1

Olaylar EDT'yi engelliyorsa, bunları EDT'de çalıştırmayın. Hala yapmaya çalıştığınız şeyin somut bir örneğini vermediniz. Hiç kullanmadım ama sen invokeAndWait (...) denedin mi? – camickr

+0

Evet, yapmıştım. “InvokeLater” ve “InvokeAndWait”, çağrıldığı konuya göre yeni etkinlik için kullanılır. – hamed

cevap

4

EventQueue'un yerini almak doğru bir yaklaşım olsa da, yerleşik EventQueue zaten öncelik tanıma özelliğini desteklediğinden bu gerçekten gerekli değildir.Tek şey, sadece içsel API kullanımı için onu destekliyor, bu yüzden sadece bunun nasıl çalıştığını anlamaya ihtiyacımız var; Eğer EventQueue görebileceğiniz gibi

//from EventQueue.java... 

private static final int LOW_PRIORITY = 0; 
private static final int NORM_PRIORITY = 1; 
private static final int HIGH_PRIORITY = 2; 
private static final int ULTIMATE_PRIORITY = 3; 

private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1; 

/* 
* We maintain one Queue for each priority that the EventQueue supports. 
* That is, the EventQueue object is actually implemented as 
* NUM_PRIORITIES queues and all Events on a particular internal Queue 
* have identical priority. Events are pulled off the EventQueue starting 
* with the Queue of highest priority. We progress in decreasing order 
* across all Queues. 
*/ 
private Queue[] queues = new Queue[NUM_PRIORITIES]; 

//...skipped some parts... 

/** 
* Causes <code>runnable</code> to have its <code>run</code> 
* method called in the {@link #isDispatchThread dispatch thread} of 
* {@link Toolkit#getSystemEventQueue the system EventQueue}. 
* This will happen after all pending events are processed. 
* 
* @param runnable the <code>Runnable</code> whose <code>run</code> 
*     method should be executed 
*     asynchronously in the 
*     {@link #isDispatchThread event dispatch thread} 
*     of {@link Toolkit#getSystemEventQueue the system EventQueue} 
* @see    #invokeAndWait 
* @see    Toolkit#getSystemEventQueue 
* @see    #isDispatchThread 
* @since   1.2 
*/ 
public static void invokeLater(Runnable runnable) { 
    Toolkit.getEventQueue().postEvent(
     new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); 
} 

/** 
* Posts a 1.1-style event to the <code>EventQueue</code>. 
* If there is an existing event on the queue with the same ID 
* and event source, the source <code>Component</code>'s 
* <code>coalesceEvents</code> method will be called. 
* 
* @param theEvent an instance of <code>java.awt.AWTEvent</code>, 
*   or a subclass of it 
* @throws NullPointerException if <code>theEvent</code> is <code>null</code> 
*/ 
public void postEvent(AWTEvent theEvent) { 
    SunToolkit.flushPendingEvents(appContext); 
    postEventPrivate(theEvent); 
} 

/** 
* Posts a 1.1-style event to the <code>EventQueue</code>. 
* If there is an existing event on the queue with the same ID 
* and event source, the source <code>Component</code>'s 
* <code>coalesceEvents</code> method will be called. 
* 
* @param theEvent an instance of <code>java.awt.AWTEvent</code>, 
*   or a subclass of it 
*/ 
private final void postEventPrivate(AWTEvent theEvent) { 
    theEvent.isPosted = true; 
    pushPopLock.lock(); 
    try { 
     if (nextQueue != null) { 
      // Forward the event to the top of EventQueue stack 
      nextQueue.postEventPrivate(theEvent); 
      return; 
     } 
     if (dispatchThread == null) { 
      if (theEvent.getSource() == AWTAutoShutdown.getInstance()) { 
       return; 
      } else { 
       initDispatchThread(); 
      } 
     } 
     postEvent(theEvent, getPriority(theEvent)); 
    } finally { 
     pushPopLock.unlock(); 
    } 
} 

private static int getPriority(AWTEvent theEvent) { 
    if (theEvent instanceof PeerEvent) { 
     PeerEvent peerEvent = (PeerEvent)theEvent; 
     if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) { 
      return ULTIMATE_PRIORITY; 
     } 
     if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) { 
      return HIGH_PRIORITY; 
     } 
     if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) { 
      return LOW_PRIORITY; 
     } 
    } 
    int id = theEvent.getID(); 
    if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) { 
     return LOW_PRIORITY; 
    } 
    return NORM_PRIORITY; 
} 

/** 
* Posts the event to the internal Queue of specified priority, 
* coalescing as appropriate. 
* 
* @param theEvent an instance of <code>java.awt.AWTEvent</code>, 
*   or a subclass of it 
* @param priority the desired priority of the event 
*/ 
private void postEvent(AWTEvent theEvent, int priority) { 
    if (coalesceEvent(theEvent, priority)) { 
     return; 
    } 

    EventQueueItem newItem = new EventQueueItem(theEvent); 

    cacheEQItem(newItem); 

    boolean notifyID = (theEvent.getID() == this.waitForID); 

    if (queues[priority].head == null) { 
     boolean shouldNotify = noEvents(); 
     queues[priority].head = queues[priority].tail = newItem; 

     if (shouldNotify) { 
      if (theEvent.getSource() != AWTAutoShutdown.getInstance()) { 
       AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); 
      } 
      pushPopCond.signalAll(); 
     } else if (notifyID) { 
      pushPopCond.signalAll(); 
     } 
    } else { 
     // The event was not coalesced or has non-Component source. 
     // Insert it at the end of the appropriate Queue. 
     queues[priority].tail.next = newItem; 
     queues[priority].tail = newItem; 
     if (notifyID) { 
      pushPopCond.signalAll(); 
     } 
    } 
} 

olarak 4 farklı kuyruklar var LOW, NORM, HIGH and ULTIMATE, SwingUtilities.invokeLater(Runnable) veya EventQueue.invokeLater(Runnable) senin RunnableInvocationEvent bir içine sarar ve postEvent(AWTEvent) yöntemini çağırır. Bu yöntem bazı iş parçacığı ve bu postEvent(theEvent, getPriority(theEvent)); gibi postEvent(AWTEvent, int) çağrıları arasında eşitleme yapar. Şimdi ilginç bölüm, PaintEvent s ve PeerEvent s ve PaintEvent s ve PeerEvent s dışında temel olay her zaman normal öncelik verir.

Yani yapmanız gereken sizin Runnable yerine böyle bir InvocationEvent ait ULTIMATE_PRIORTY ile PeerEvent içine sarmak olduğu;

Toolkit.getDefaultToolkit().getSystemEventQueue() 
    .postEvent(new PeerEvent(Toolkit.getDefaultToolkit(),() -> { 


    //execute your high priority task here! 
    System.out.println("I'm ultimate prioritized in EventQueue!"); 


}, PeerEvent.ULTIMATE_PRIORITY_EVENT)); 

Sen EventQueue ve PeerEvent tam kaynak kodunu kontrol edebilirsiniz.

+0

Bu tam olarak aradığım şey. Teşekkürler @Onur – hamed

2

Benim ilk düşüncem oldu

Bence Olay Sevk Takip tarafından alınmayı ihtiyacı görevleri kontrol edebilirsiniz sanmıyorum ama belli şekillerde biz

aşağıda gibi önceliğini ayarlamak için deneyebilirsiniz Yine EDT'nin derhal icra edilmesi için alınacağının bir garantisi yoktur.

Ancak yukarıdaki kod yanlıştır. Zamana göre denir, zaten görevleri yerine getirir. Onur için teşekkürler.

Aşağıdaki kod, yardımcı olmalıdır.

EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
    Runnable runnable = new Runnable() { 

     @Override 
     public void run() { 
      //My high priority task 
     } 
    }; 
    PeerEvent event = new PeerEvent(this, runnable, PeerEvent.ULTIMATE_PRIORITY_EVENT); 
    queue.postEvent(event); 

Ancak dikkat edilmesi gereken bir nokta var.

private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1; 

    /* 
    * We maintain one Queue for each priority that the EventQueue supports. 
    * That is, the EventQueue object is actually implemented as 
    * NUM_PRIORITIES queues and all Events on a particular internal Queue 
    * have identical priority. Events are pulled off the EventQueue starting 
    * with the Queue of highest priority. We progress in decreasing order 
    * across all Queues. 
    */ 
    private Queue[] queues = new Queue[NUM_PRIORITIES]; 

    public EventQueue() { 
     for (int i = 0; i < NUM_PRIORITIES; i++) { 
      queues[i] = new Queue(); 
     } 
    .... 
    } 

yüzden çok fazla ULTIMATE_PRIORITY görevleri ayarlarken eğer, son görevi hemen infaz edileceğini garantisi yoktur.

+0

Bu kod, Runnable'ın/Task'ın priory'sini ayarlamıyor. Etkinlik Gönderi İpliği'nin önceliği maksimum değere ayarlanır. Bu sadece geçerli görevi etkilemekle kalmaz, aynı zamanda kuyruktaki diğer tüm görevleri de etkiler. – Onur

+0

@Onur Yorumlarınızdan hemen sonra fark ettim. Öğrenmeme yardım ettiğin için teşekkürler. – Beniton

+0

bir şey değil, ama Java'nın iç API'si asla kullanmıyor ** ULTIMATE_PRIORITY **. Burada görebilirsiniz: [sun.awt.PeerEvent kullanımı] (http://grepcode.com/search/[email protected][email protected]@sun$ awt @ PeerEvent & type = type & k = u) PeerEvent' her zaman ** PeerEvent.PRIORITY_EVENT' ile yaratılır ** – Onur

2

Yeni olayları istediğiniz şekilde ekleyen kendi Etkinlik Kuyruğunu oluşturabilir ve kullanabilirsiniz. nasıl kurulum özel bir olay Kuyruğu altında kod parçacığını bakınız:

public class QueueTest { 
    public static void main(String[] args) throws InterruptedException, InvocationTargetException { 
     EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); 
     eventQueue.push(new MyEventQueue()); 

     EventQueue.invokeAndWait(new Runnable() { 
      public void run() { 
       System.out.println("Run"); 
      } 
     }); 
    } 

    private static class MyEventQueue extends EventQueue { 
     public void postEvent(AWTEvent theEvent) { 
      System.out.println("Event Posted"); 
      super.postEvent(theEvent); 
     } 
    } 
} 

Size özel Olay Kuyruk olabilir en yüksek önceliğe sahip kuyruğuna başına eklenecektir istediğiniz ardından gönderme belirli olaylar. Bu, işlenecek bir sonraki olayın olmasını sağlamayabilir, ancak muhtemelen mevcut tasarıma en iyi şekilde uyacaktır.

İlgili konular