3

I am looking for a way to do what the InvokeLater() function does only instead of putting the event on the bottom of the event queue it puts it on top. At least I think that will do what I want, maybe there's a better way. Below describes what I'm trying to replicate.

Years ago I use a c++ framework on the Mac that had feature that you could add a Chore object to a CriticalChore list while processing the current event. You would do this while executing code in what amounts to Swings EDT. After the current event was finished being processed and just before calling GetNextEvent() the Framework would check if the CriticalChore list was empty. If the list had items in it there Perform() (i.e. run()) function would be called. When finished with the list all the items were then deleted.

This feature came in really handy. Many times while handling an event early on you know you need to perform some additional code but only after a lot of other code is processed. But most importantly, is this code needs to be processed before any other events from the EDT queue are handled.

Chris Dennett
  • 22,412
  • 8
  • 58
  • 84
mretondo
  • 31
  • 2

2 Answers2

1

I don't see any method of doing that. I suppose that you could do some hacky stuff to make your own method of injecting higher priority actions.

I think the best answer, though, is to not do this at all. If you have a need to do so, the design probably needs to be reworked. The EventDispatchThread is supposed to be only for very short-running actions as it's never supposed to look to the end user as though the application has frozen. Because of this, the queue for the EDT should always be short enough that anything you put on it will happen "instantly" from the point of view of the user, so everything on it should have "instant" priority.

If anything needs to be done which is not a very short-lived action, there is a separate methodology for doing that. There is a Swing Worker class for that, and you are supposed to use this to set up tasks that run alongside the EDT and listen for its responses.

Here is a Swing Worker Tutorial. There are also some other good ones that Google pulls up with a "Java SwingWorker tutorial" query.

Loduwijk
  • 1,950
  • 1
  • 16
  • 28
  • This isn't used for long lasting code. It usually is only a few line of code. Most of the time it's just a post i.e. invokeLater(). Early on you need to post an event but you want to make sure it's the last event posted done while executing the current event. There might or might not be events posted in the code to come. – mretondo Jun 30 '11 at 19:24
1

First, how's done

It's possible to install a global listener with its own queue and one each event polling the queue. Toolkit.addAWTEventListener(listener, eventMask)

There is a sun.awt.PeerEvent (for sun impl) that has an ultimate priority which offers the easiest impl since it's practically the same as EventQueue.invokeLater extending java.awt.event.InvocationEvent but again it's not standard.

Last: Here how is done standard way, I have not tested the code, though (lazy & very late)

  class EventQueueX extends EventQueue{
        final ConcurrentLinkedQueue<AWTEvent> que=new ConcurrentLinkedQueue<AWTEvent>();

        @Override
        public AWTEvent getNextEvent() throws InterruptedException {
            AWTEvent e = que.poll();
            if (e!=null)
                return e;
            return super.getNextEvent();
        }
        @Override
        public synchronized AWTEvent peekEvent() {
            AWTEvent e = que.peek();
            if (e!=null)
                return e;
            return super.peekEvent();
        }

        public void pushFirst(AWTEvent e){
            que.offer(e);
            synchronized (this) {
                    notify();
                }
        }
        public void install(Toolkit toolkit){
            EventQueue q = toolkit.getSystemEventQueue();           
            if (q!=this)
                q.push(this);
        }
    };

Use the EventQueueX.install() and then pushFirst(e) when you want an event and you're set. Unfortunately the queue will get deinstalled on an exception and might be pushed away too.

Next, why is bad To the question. putting an event in the front of the queue is a bad idea overall. If you have to call any code later on just structure your own design and at the end of the function invoke the necessary code, use a Queue if you need be.

Adding an extra layer of super ultimate priority might look ok, but it's a hard to understand design concept for any regular AWT/Swing (UI mostly) developer. If you need to queue actions, use your own mini-framework w/o messing up with awt. While I am particularly good at hacking, even I, myself, would fine such an approach weird (to put it mildly).

bestsss
  • 11,796
  • 3
  • 53
  • 63
  • Your point is well taken but it assumes I'm the only coder. In reality I'm one of many. Over the course of 4-5 years 5-10 coders have there hands in there adding new functionality or bug fixing. They most likely have no idea of the hole picture of the code from the moment the event was handled until it's complete. Many times you fix a bug in a function that gets called for multiple events. That coder has no idea he just broke your clean structure by throwing in an invokeLater(). – mretondo Jun 30 '11 at 19:47
  • @mretondo, I missed that part in the reply. Most of the time when you are in AWT event processing, invokeLater() is almost always the next event. Perhaps some OS type of event can be processed but that should not really alter the logic. – bestsss Jun 30 '11 at 19:53
  • Oh, thanks for your reply. I wasn't looking for any hacks. I was just looking for a legit way of doing what I needed. For all I new there was a mechanism in place already and I didn't know it. But I still learned some things from your example and that's always a good thing! – mretondo Jun 30 '11 at 19:56