我有一个要在基于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的一部分,我将通过显示表单来处理异常。该特定事件将被使用,但是在重新认证之后,我可以将同一事件重新分发给应用程序,或者将其推送到事件队列中。
自从我假定该事件具有指示该事件是否已发布和使用的标志以来,这两种方法均失败。
很抱歉,格式不好用,我还没弄清楚标记。
在这里的任何帮助,将不胜感激。
修正:感谢您的所有回答。解决方法(我自己找不到)是在进行呼叫时捕获会话超时异常。该应用程序会弹出一个对话框,要求用户重新进行身份验证。身份验证成功后,对话框将关闭。它使我惊讶。
我不确定,但似乎在显示对话框时事件仍停留在队列中,并且一旦关闭对话框,它将传递到控件中,无论如何都会如此。
最佳答案
我不会尝试从事件角度解决此问题。事件系统并非以这种方式工作。
我将定义一个封装与服务器交互的接口(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();
}
}