gpt4 book ai didi

java - 如何在 java 中重新发送任何 AWTEvent?

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:03:41 26 4
gpt4 key购买 nike

我有一项功能要在基于 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);
}
}

所需的功能是能够使用户 session 超时。当 session 超时时,服务器将抛出一个特定的异常。超时时,系统会提示用户重新登录,被中止的原始操作将继续进行。我想做的是,作为 onError 的一部分,我将通过显示表单来处理异常。该特定事件将被消耗,但在重新验证后,我可以将同一事件重新分配给应用程序,或者可能将其推送到事件队列中。这两种方法都失败了,因为我假设该事件具有指示它是否已发布和使用的标志。

  1. 通过的事件可以是任何事件(无论是鼠标还是击键)。
  2. 定义自定义事件并不能解决他们的问题,因为我需要重播同一事件。
  3. 我考虑过克隆事件,但 AWTEvent 不支持克隆。
  4. 通过序列化然后反序列化事件的深度复制不起作用,因为一些正在分派(dispatch)的事件不可序列化。
  5. 我正在考虑通过反射重置事件中的任何状态变量,但这似乎很危险。

对于糟糕的格式感到抱歉,我还没有想出标记。如有任何帮助,我们将不胜感激。

修正:感谢您的所有回答。修复(不是我自己找到的)是在调用时捕获 session 超时异常。应用程序弹出一个对话框,要求用户重新进行身份验证。认证成功后,对话框关闭。效果出乎我的意料。

我不确定,但似乎在显示对话框时事件仍然停留在队列中,一旦对话框关闭,它就会被传送到控件。

最佳答案

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

我会定义一个接口(interface) (X) 来封装与服务器的交互。实现 Y 将保存上次服务器请求的参数。超时后,用户重新认证,然后我可以让 Y 重新发送最后一个请求。

额外的好处:由于 X 是一个接口(interface),这简化了测试,因为 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();
}
}

关于java - 如何在 java 中重新发送任何 AWTEvent?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3109916/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com