gpt4 book ai didi

java - Swing 中的事件调度过滤器链

转载 作者:行者123 更新时间:2023-11-30 09:44:03 25 4
gpt4 key购买 nike

我正在尝试组织 filter chainEventQueue.dispatchEvent .类似于 java.io.FilterInputStreamjavax.servlet.Filter .

找到 EventQueueDelegate.Delegate用于此目的?.. 但是如果 EventQueue.dispatchEvent EventQueueDelegate.Delegate 中出现异常,它对此一无所知并且丑陋 java.awt.EventDispatchThread .handleException 出现在现场。

  • 自 Java SE 1.1 以来,这个“临时黑客”还没有解决吗???!!!

我也看过 EventQueue.dispatchEvent在链中调用。但它似乎不适合这个,因为这种方法是 protected ,它需要额外的手鼓舞蹈才能使事情正常进行,代码变得不那么可爱。

  • 有更好的解决方案吗?

最佳答案

接下来是围绕 EventQueueDelegate.Delegate 手鼓跳舞...

AwtExceptionHandler.java

package example;

/**
* @see java.awt.EventDispatchThread#handleException(Throwable thrown)
*/
public interface AwtExceptionHandler {
void handle(Throwable t) throws Throwable;
}

FilterEventQueueDelegate.java

package example;

import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.lang.reflect.Method;
import java.util.ConcurrentModificationException;

import sun.awt.EventQueueDelegate;

/**
* Aims to organise filter chain of {@link EventQueueDelegate.Delegate}.
*
* <pre>
* private static final AwtResponsivenessMonitor instance = FilterEventQueueDelegate.chain(new AwtResponsivenessMonitor());
* </pre>
*
* @author Mykhaylo Adamovych
*/
public abstract class FilterEventQueueDelegate implements EventQueueDelegate.Delegate, AwtExceptionHandler {
public static final class ExceptionHandler {
private static AwtExceptionHandler currentExceptionHandler;

public void handle(Throwable t) throws Throwable {
currentExceptionHandler.handle(t);
}
}

private static final class SimpleFilterEventQueueDelegate extends FilterEventQueueDelegate {
private EventQueueDelegate.Delegate thirdPartyDelegate;
private Object thirdPartyExceptionHandler;

@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
if (thirdPartyDelegate != null)
thirdPartyDelegate.afterDispatch(arg0, arg1);
}

@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
if (thirdPartyDelegate != null)
return thirdPartyDelegate.beforeDispatch(arg0);
return arg0;
}

@Override
public AWTEvent getNextEvent(EventQueue arg0) throws InterruptedException {
if (thirdPartyDelegate != null)
return thirdPartyDelegate.getNextEvent(arg0);
return arg0.getNextEvent();
}

@Override
public void handle(Throwable t) throws Throwable {
if (thirdPartyExceptionHandler != null)
try {
Class<? extends Object> c = thirdPartyExceptionHandler.getClass();
Method m = c.getMethod("handle", new Class[] { Throwable.class });
m.invoke(thirdPartyExceptionHandler, new Object[] { t });
} catch (Throwable x) {
thirdPartyExceptionHandler = null; /* Do not try this again */
throw t;
}
else
throw t;
}

public void setEventQueueDelegate(EventQueueDelegate.Delegate delegate) {
thirdPartyDelegate = delegate;
}

public void setExceptionHandler(Object exceptionHandler) {
thirdPartyExceptionHandler = exceptionHandler;
}
}

public static <T extends FilterEventQueueDelegate> T chain(T delegate) {
synchronized (EventQueueDelegate.class) {
EventQueueDelegate.Delegate currentDelegate = EventQueueDelegate.getDelegate();
FilterEventQueueDelegate currentFilterDelegate = null;
if (currentDelegate instanceof FilterEventQueueDelegate)
currentFilterDelegate = (FilterEventQueueDelegate) currentDelegate;
else {
SimpleFilterEventQueueDelegate simpleFilterDelegate = new SimpleFilterEventQueueDelegate();
if (currentDelegate != null)
simpleFilterDelegate.setEventQueueDelegate(currentDelegate);
Object currentExceptionHandler = null;
try {
currentExceptionHandler = Class.forName(System.getProperty("sun.awt.exception.handler")).newInstance();
} catch (Exception e) {
}
if (currentExceptionHandler != null)
simpleFilterDelegate.setExceptionHandler(currentExceptionHandler);
System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
currentFilterDelegate = simpleFilterDelegate;
}
delegate.setNext(currentFilterDelegate);
EventQueueDelegate.setDelegate(delegate);
if (EventQueueDelegate.getDelegate() != delegate)
throw new ConcurrentModificationException();
ExceptionHandler.currentExceptionHandler = delegate;
return delegate;
}
}

protected FilterEventQueueDelegate next;

@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
next.afterDispatch(arg0, arg1);
}

@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
return next.beforeDispatch(arg0);
}

@Override
public AWTEvent getNextEvent(EventQueue arg0) throws InterruptedException {
return next.getNextEvent(arg0);
}

@Override
public void handle(Throwable t) throws Throwable {
next.handle(t);
}

private void setNext(FilterEventQueueDelegate eventQueueDelegate) {
next = eventQueueDelegate;
}
}

AwtResponsivenessMonitor.java

package example;

import java.awt.AWTEvent;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
* Monitors {@code EventDispatchThread} responsiveness.
* <p>
* Singleton is initialised on first access.
*
* @author Mykhaylo Adamovych
*/
public class AwtResponsivenessMonitor extends FilterEventQueueDelegate {
private static final class DeamonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread result = new Thread(r);
result.setName(AwtResponsivenessMonitor.class.getSimpleName());
result.setDaemon(true);
return result;
}
}

private static final class NotResponsive extends RuntimeException {
private static final long serialVersionUID = -1445765918431458354L;
}

public static final long DEFAULT_RESPONSIVENESS_TIMEOUT_S = 2;
public static final long RESPONSIVENESS_WATCHDOG_MS = 50;
private static final AwtResponsivenessMonitor instance = FilterEventQueueDelegate.chain(new AwtResponsivenessMonitor());

public static AwtResponsivenessMonitor getInstance() {
return instance;
}

public static long getResponsivenessTimeout() {
return instance.responsivenessTimeoutMs.get();
}

public static void setResponsivenessTimeout(long timeoutMs) {
instance.responsivenessTimeoutMs.set(timeoutMs);
}

private final AtomicLong responsivenessTimeoutMs = new AtomicLong(TimeUnit.SECONDS.toMillis(DEFAULT_RESPONSIVENESS_TIMEOUT_S));
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new DeamonThreadFactory());
private long eventDispatchStartTime;
private Thread currentWorkingThread;

public AwtResponsivenessMonitor() {
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
checkResponsiveness();
}
}, RESPONSIVENESS_WATCHDOG_MS, RESPONSIVENESS_WATCHDOG_MS, TimeUnit.MILLISECONDS);
}

@Override
public synchronized void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
eventDispatchStartTime = 0;
super.afterDispatch(arg0, arg1);
}

@Override
public synchronized Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
eventDispatchStartTime = System.currentTimeMillis();
currentWorkingThread = Thread.currentThread();
return super.beforeDispatch(arg0);
}

private synchronized void checkResponsiveness() {
if (eventDispatchStartTime != 0 && currentWorkingThread != null && System.currentTimeMillis() > eventDispatchStartTime + responsivenessTimeoutMs.get()) {
Exception e = new NotResponsive();
e.setStackTrace(currentWorkingThread.getStackTrace());
e.printStackTrace();
currentWorkingThread = null;
}
}

@Override
public synchronized void handle(Throwable t) throws Throwable {
eventDispatchStartTime = 0;
super.handle(t);
}
}

AwtIdleTracker.java

package example;

import java.awt.AWTEvent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;

import javax.swing.SwingUtilities;

import sun.awt.SunToolkit;

/**
* Tracks {@code EventDispatchThread} idleness.
* <p>
* Singleton is initialised on first access.
*
* @author Mykhaylo Adamovych
*/
public class AwtIdleTracker extends FilterEventQueueDelegate {
public static final long DEFAULT_IDLE_TIME_TO_TRACK_MS = 1000;
private static final long IDLE_TIME_WATCHDOG_MS = 10;
private static final AwtIdleTracker instance = FilterEventQueueDelegate.chain(new AwtIdleTracker());

public static AwtIdleTracker getInstance() {
return instance;
}

private volatile boolean inProgress;
private final AtomicLong lastDispatchTime = new AtomicLong(0);

@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
lastDispatchTime.set(System.currentTimeMillis());
inProgress = false;
super.afterDispatch(arg0, arg1);
}

@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
inProgress = true;
return super.beforeDispatch(arg0);
}

@Override
public void handle(Throwable t) throws Throwable {
lastDispatchTime.set(System.currentTimeMillis());
inProgress = false;
super.handle(t);
}

public boolean isIdle() {
return this.isIdle(DEFAULT_IDLE_TIME_TO_TRACK_MS);
}

public boolean isIdle(long idleTimeToTrackMs) {
return !inProgress && SunToolkit.isPostEventQueueEmpty() && System.currentTimeMillis() > lastDispatchTime.get() + idleTimeToTrackMs;
}

public void waitForIdle() {
waitForIdle(DEFAULT_IDLE_TIME_TO_TRACK_MS);
}

public void waitForIdle(long idleTimeToTrackMs) {
waitForIdle(idleTimeToTrackMs, TimeUnit.DAYS.toMillis(365));
}

public void waitForIdle(long idleTimeToTrackMs, long timeoutMs) {
if (SwingUtilities.isEventDispatchThread())
throw new IllegalAccessError();
long staleThreshold = System.currentTimeMillis() + timeoutMs;
while (!isIdle(idleTimeToTrackMs)) {
if (System.currentTimeMillis() > staleThreshold)
throw new RuntimeException("GUI still is not idle.");
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(IDLE_TIME_WATCHDOG_MS));
}
}
}

例子.java

package example;

import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

import sun.awt.EventQueueDelegate;

public class Example {
public static class ThirdPartyEventQueueDelegate implements EventQueueDelegate.Delegate {
public static final void registerEventQueueDelegate() {
EventQueueDelegate.setDelegate(new ThirdPartyEventQueueDelegate());
}

@Override
public void afterDispatch(AWTEvent arg0, Object arg1) throws InterruptedException {
System.out.println("Third party even queue delegate was not broken.");
}

@Override
public Object beforeDispatch(AWTEvent arg0) throws InterruptedException {
return arg0;
}

@Override
public AWTEvent getNextEvent(EventQueue arg0) throws InterruptedException {
return arg0.getNextEvent();
}
}

public static class ThirdPartyExceptionHandler {
public static void registerExceptionHandler() {
System.setProperty("sun.awt.exception.handler", ThirdPartyExceptionHandler.class.getName());
}

public void handle(Throwable t) {
System.out.println("Third party Exception handler was not broken.");
}
}

private static boolean wasIdle = false;
private static boolean isFistTime = true;

public static synchronized void log(String msg) {
System.out.println(new SimpleDateFormat("mm:ss.SSS").format(new Date()) + "\t" + msg);
}

public static void main(String[] args) {
// let suppose there are some related stuff already
ThirdPartyExceptionHandler.registerExceptionHandler();
ThirdPartyEventQueueDelegate.registerEventQueueDelegate();
// initialise singletons, build filter chain
AwtIdleTracker.getInstance();
AwtResponsivenessMonitor.setResponsivenessTimeout(TimeUnit.SECONDS.toMillis(2));
testWaitForIdle();
// testSomeGui();
}

public static void testSomeGui() {
// some test with visible GUI
JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
while (true) {
boolean isIdle = AwtIdleTracker.getInstance().isIdle();
if (isFistTime || wasIdle != isIdle) {
isFistTime = false;
wasIdle = isIdle;
String msg = isIdle
? "idle"
: "busy";
log("system becomes " + msg);
}
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1));
}
}

public static void testWaitForIdle() {
// some long operation
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
log("task started");
// throw new RuntimeException();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
log("task finished");
}
});
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
log("started waiting for idle");
AwtIdleTracker.getInstance().waitForIdle();
log("stopped waiting for idle");
}
}

关于java - Swing 中的事件调度过滤器链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8080018/

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