I wonder no more!
Copy the following (ctrl-C), then activate some package node in a project in Eclipse (e.g. the obvious "com.example") and paste (ctrl-V).
import java.awt.Component;Code discussion: The
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
public class DebugStatics {
public interface LineTaker {
void line(String msg);
}
public static final void main(String[] args) {
LineTaker out = new LineTaker() {
@Override
public void line(String msg) {
System.out.println(msg);
}
};
addDebugListeners(out, new JButton(), false);
}
public static void addDebugListeners(final LineTaker out, final Object component,
final boolean includeAllMoveEvents) {
// :: Find all add*Listener methods for supplied component.
List<Class<?>> listenerInterfaces = new ArrayList<Class<?>>();
List<Method> addListenerMethods = new ArrayList<Method>();
Method[] methods = component.getClass().getMethods();
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("add") && name.endsWith("Listener")) {
Class<?>[] parameters = method.getParameterTypes();
if (parameters.length == 1) {
Class<?> interfaze = parameters[0];
if (interfaze.isInterface()) {
listenerInterfaces.add(interfaze);
addListenerMethods.add(method);
}
}
}
}
// :: Make handler for "super listener"
InvocationHandler handler = new InvocationHandler() {
long _lastEvent;
String _lastMethodName;
boolean _threadFired;
InvocationHandler _handler = this;
@Override
public synchronized Object invoke(@SuppressWarnings ("unused") Object proxy, Method method, Object[] args)
throws Throwable {
_lastEvent = System.currentTimeMillis();
String methodName = method.getName();
if (includeAllMoveEvents || !(methodName.endsWith("Moved") && methodName.equals(_lastMethodName))) {
out.line("event:[" + method.getName() + "] - on - [" + method.getDeclaringClass().getName()
+ "] - with - " + Arrays.asList(args) + ".");
if (!_threadFired) {
_threadFired = true;
new Thread("debug:Event Stream Breaker") {
@Override
public void run() {
while (true) {
long millisLeft;
synchronized (_handler) {
millisLeft = 400 - (System.currentTimeMillis() - _lastEvent);
if (millisLeft < 0) {
out.line("===== event stream break.");
_threadFired = false;
_lastMethodName = null;
break;
}
}
try {
Thread.sleep(millisLeft + 2);
continue;
}
catch (InterruptedException e) {
break;
}
}
}
}.start();
}
}
_lastMethodName = methodName;
return null;
}
};
// :: Make "super listener", "implementing" all the Listener interfaces
Object superListener = Proxy.newProxyInstance(DebugStatics.class.getClassLoader(), listenerInterfaces
.toArray(new Class<?>[0]), handler);
// :: Attach "super listener" using all add*Listener methods on supplied component
for (Method method : addListenerMethods) {
try {
method.invoke(component, superListener);
out.line(" ++ add*Listener: [" + method + "].");
}
catch (Throwable e) {
out.line("Got error when trying to invoke add*Listener method:[" + method + "]." + e);
}
}
}
}
LineTaker
comes from the need to have some flexibility regarding where the textual stream of events should end up (e.g. to System.out.println(...)
or to some logger.debug(...)
). The driver (main
method) is just to check out the listener adding (and possibly also to find out which types of add*Listener methods a given AWT/Swing/Whatever class has). The reason for the Thread
-forking is so that you more easily can understand which events "belongs" to each actual, physical gesture: Move the mouse into a button, wait a second, then press down mouse button, wait a second, release mouse button, wait a second, move out. Now the result event stream have embedded a break on every second-wait. The thread only lives long enough to write the break, then exits. The reason for the code regarding move-events suppression is that you get an awful lot of move-events without it - this code results in only one move event being recorded in a consecutive run of the same move event.While dumping the code into this post, it hit me that the above method actually works for any class having
add*Listener(AnyInterface listener)
methods. That's why the type of the component
argument is Object
.There's a pretty impressive amount of events being fired on a JButton for the simple act of using the mouse to click it!
Công việc văn phòng luôn tạo cho nhân viên căng thẳng áp lực.Nên cần thay đổi không gian làm việc bằng cách tựtạo cảm hứng làm việc với bàn làm việc
ReplyDeleteBạn đang có nnhu cầu mua bàn làm việc thì việc đầu tiên bạn nên trang bị kiến thứccách chọn bàn làm việc
Tìm hiểu thông tin và tiêu chỉ để có thể chọn bàn làm việc văn phòng
Nội thất văn phòng trong công ty doanh nghiệp ghế, tủ, hộc hồ sơ...và không thể thiếubàn làm việc trong văn phòng công ty
Cũng như các sản phẩm văn phòng khác truóc khi mua bạn nên xem qua và chọn mẫu ưng ý.Và đối với bàn làm việc cũng thế khi mua bạn nênnên chọn mẫu bàn làm việc
Really this article is truly one of the best in article history and am a collector of old "items" and sometimes read new items if i find them interesting which is one that I found quite fascinating and should be part of my collection. Very good work!
ReplyDeleteData Scientist Course in Gurgaon
I am hoping the same best effort from you in the future as well and in fact your creative writing skills has inspired me.
ReplyDeleteData Science Course near me
Nice Post thank you very much for sharing such a useful information and will definitely saved and revisit your site and i have bookmarked to check out new things frm your post.
ReplyDeleteData Science Course
Just a shine from you here and have never expected anything less from you and have not disappointed me at all which i guess you will continue the quality work. Great post.
ReplyDeleteData Science Training in Gurgaon
Interesting post. which i wondered about this issue so thanks for posting and very good article which is a really very nice and useful article. Thank you
ReplyDeleteData Science Course in Noida
Very great post which I really enjoy reading this and it is not everyday that I have the possibility to see something like this. Thank You.
ReplyDeleteBest Online Data Science Courses
I read your excellent blog post. It's a great job. I enjoyed reading your post for the first time, thank you.
ReplyDeleteData Science Institutes in Bangalore
Well done for this excellent article. and really enjoyed reading this article today it might be one of the best articles I have read so far and please keep this work of the same quality.
ReplyDeleteData Analytics Course in Noida
Informative Post. The information you have posted is very useful and sites you have referred was good. Thanks for sharing.
ReplyDeleteData Science Course with Placement
I am always searching online for articles that can help me and you made some good points in Features also. Keep working, great job
ReplyDeleteData Science Training