简体   繁体   English

在 Swing 中,您可以将事件发布到 EDT 事件队列的顶部吗?

[英]In Swing can you post an event to the top of the EDT events queue?

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.我正在寻找一种方法来执行 InvokeLater() function 所做的事情,而不是将事件放在事件队列的底部,而是将其放在顶部。 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.几年前,我在 Mac 上使用了 c++ 框架,该框架具有可以在处理当前事件时将杂项 object 添加到关键杂项列表的功能。 You would do this while executing code in what amounts to Swings EDT.您可以在执行相当于 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.在当前事件完成处理之后,就在调用 GetNextEvent() 之前,框架将检查 CriticalChore 列表是否为空。 If the list had items in it there Perform() (ie run()) function would be called.如果列表中有项目,则将调用 Perform()(即 run())function。 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.但最重要的是,是否需要在处理 EDT 队列中的任何其他事件之前处理此代码。

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.我想你可以做一些 hacky 的东西来制作你自己的注入更高优先级操作的方法。

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. EventDispatchThread 应该只用于运行时间很短的操作,因为它永远不会让最终用户看起来好像应用程序已冻结。 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.正因为如此,EDT 的队列应该总是足够短,以至于从用户的角度来看,你放在它上面的任何东西都会“立即”发生,所以它上面的所有东西都应该具有“即时”优先级。

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.为此有一个Swing Worker class,您应该使用它来设置与 EDT 一起运行的任务并监听其响应。

Here is aSwing Worker Tutorial .这是Swing 工人教程 There are also some other good ones that Google pulls up with a "Java SwingWorker tutorial" query. Google 还通过“Java SwingWorker 教程”查询提取了其他一些不错的内容。

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.有一个sun.awt.PeerEvent (对于 sun impl)具有ultimate priority ,它提供了最简单的 impl,因为它实际上与 EventQueue.invokeLater 扩展java.awt.event.InvocationEvent相同,但它又不是标准的。

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.当你想要一个事件并且你已经设置好时,使用EventQueueX.install()然后pushFirst(e) 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.如果您稍后必须调用任何代码,只需构建您自己的设计,并在 function 结束时调用必要的代码,如果需要,请使用队列。

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.添加一个额外的超级最终优先级可能看起来不错,但对于任何常规 AWT/Swing(主要是 UI)开发人员来说,很难理解设计概念。 If you need to queue actions, use your own mini-framework w/o messing up with awt.如果您需要对操作进行排队,请使用您自己的迷你框架,而不会弄乱 awt。 While I am particularly good at hacking, even I, myself, would fine such an approach weird (to put it mildly).虽然我特别擅长黑客攻击,但即使是我自己,也会认为这种方法很奇怪(委婉地说)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM