我有一个要在基于Java 1.5 Swing的应用程序中实现的功能。
如果在处理AWTEvent时发生特殊异常,我必须弹出备用表格,解决问题,然后继续处理原始事件。
当我将事件重新分发给组件时,什么也没有发生。当我将事件推送到事件队列时,什么也没有发生。我假设事件中有一些状态字段将其标记为已处理,因此组件不会选择它。
到目前为止,我找不到重新创建该事件的副本的方法。自定义事件在这里无济于事,因为我希望处理上一个事件。

在swing应用程序中,现有事件队列被内部队列替换。

private class ApplicationEventQueue extends EventQueue
{
    private final ArrayList listeners=new ArrayList();
    protected void initialize()
    {
        Toolkit.getDefaultToolkit().getSystemEventQueue().push(this);
    }
.
.
.
}

As part of the dispatch event, The class intercepts the call ans delegates to the super class. If an exception occurs it will pop-up a messagebox with a "sorry for the inconvienience" message.

@Override
protected void dispatchEvent(AWTEvent event)
{
    try
    {
        super.dispatchEvent(event);
        if (peekEvent() != null && userEventDispatched)
        {
            raiseIdleEvent();
            userEventDispatched = false;
        }
        else
        {
            int eventId = event.getID();
            if (eventId == KeyEvent.KEY_TYPED || eventId == MouseEvent.MOUSE_CLICKED)
            {
                userEventDispatched = true;
            }
        }
    }
    catch (Throwable ex)
    {
        onError(ex);
    }
}

所需的功能是能够使用户会话超时。会话超时时,服务器将引发特定异常。超时后,系统将提示用户重新登录,并且将继续执行中止的原始操作。
我想做的是,作为onError的一部分,我将通过显示表单来处理异常。该特定事件将被使用,但是在重新认证之后,我可以将同一事件重新分发给应用程序,或者将其推送到事件队列中。
自从我假定该事件具有指示该事件是否已发布和使用的标志以来,这两种方法均失败。
  • 发生的事件可以是任何事件(无论是击键的鼠标)。
  • 定义自定义事件不会解决它们的问题,因为我需要重播同一事件。
  • 我已经考虑过克隆事件,但是AWTEvent不支持克隆。
  • 通过序列化然后反序列化该事件的深层复制不起作用,因为分派的某些事件无法序列化。
  • 我正在考虑通过反射重置事件中的任何状态变量,但这似乎很危险。

  • 很抱歉,格式不好用,我还没弄清楚标记。
    在这里的任何帮助,将不胜感激。

    修正:感谢您的所有回答。解决方法(我自己找不到)是在进行呼叫时捕获会话超时异常。该应用程序会弹出一个对话框,要求用户重新进行身份验证。身份验证成功后,对话框将关闭。它使我惊讶。

    我不确定,但似乎在显示对话框时事件仍停留在队列中,并且一旦关闭对话框,它将传递到控件中,无论如何都会如此。

    最佳答案

    我不会尝试从事件角度解决此问题。事件系统并非以这种方式工作。

    我将定义一个封装与服务器交互的接口(X)。实现Y将保存上一个服务器请求的参数。发生超时并且用户已重新认证后,我可以要求Y重新发送上一个请求。

    额外的好处:由于X是一个接口,因此可以简化测试,因为可以用模拟对象代替Y来测试GUI,并且测试代码可以在没有GUI的情况下调用Y。

    更新:

    这是一种使用SwingWorker在bg线程上运行服务器交互的方法。 ChangeEvent用于将结果返回给EDT进行处理。 SwingWorker的发布/过程用于处理用户交互以进行重新认证。 SwingWorker的一个好处是,如果服务器需要很长时间来响应,则UI仍可以响应重绘事件。

    class Test extends JPanel {
        private JButton b;
        public Test() {
            b = new JButton(new AbstractAction("Do something") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    final JButton btn = (JButton) e.getSource();
                    btn.setEnabled(false);
                    Object req = new Object(); // Replace w/ apropriate type
                    new RequestDispatch(req, new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
                            final Object req = e.getSource();
                            // Do something with data from 'req'
                            btn.setEnabled(true);
                        }
                    });
                }
            });
            add(b);
        }
    }
    
    class RequestDispatch extends SwingWorker<Object, Void> {
        private enum DispatchState { Ready, Running, Canceled }
        private final ChangeListener listener;
        private DispatchState dstate = DispatchState.Ready;
        private final Object req;
        RequestDispatch(Object req, ChangeListener listener)
        {
            this.req = req;
            this.listener = listener;
            execute();
        }
        @Override
        protected Object doInBackground() throws Exception {
            while (true) {
                DispatchState st = getDState();
                if (st == DispatchState.Ready)
                {
                    try {
                        setDstate(DispatchState.Running);
                        // send request to the server, update req with response
                        return req;
                    }
                    catch (TimeoutException ex) {
                        this.publish((Void)null);
                        synchronized (this) {
                            wait();
                        }
                    }
                }
                if (st == DispatchState.Canceled) {
                    return req;
                }
            }
        }
        @Override
        protected void process(List<Void> chunks) {
            // Session has timed out
            // Ask the user to re-authenticate
            int result = JOptionPane.showConfirmDialog(null, "Login");
            if (result == JOptionPane.CANCEL_OPTION) {
                setDstate(DispatchState.Canceled);
            }
            else {
                setDstate(DispatchState.Ready);
            }
        }
        private synchronized DispatchState getDState() {
            return dstate;
        }
        private synchronized void setDstate(DispatchState dstate) {
            this.dstate = dstate;
            notifyAll();
        }
    }
    

    07-24 09:38
    查看更多