java - How to request focus synchronously in Swing? -
when call component.requestfocusinwindow()
, swing enqueues asynchronous focus_gained
, focus_lost
events rather synchronously transferring focus. workaround, appears defaultkeyboardfocusmanager
trying simulate synchronously switching focus delaying dispatch of keyboard events until focus events have finished dispatching. appears isn’t working properly.
question: there way change focus synchronously in swing? defaultkeyboardfocusmanager
trying simulate synchronous focus, , buggy? there focus manager correctly?
motivation: have jtextfield
automatically transfers focus when it’s full. in writing integration tests using java.awt.robot
, need behavior deterministic , not timing-dependent.
related question didn’t response: how grab focus now?
here’s demo. expected behavior: when hold down key, each jtextfield
contain single character. actual behavior: focus not change fast enough multiple characters.
update: note behavior not specific progammatically changing focus. in third example, took out custom focus calls , instead set document update delay 500ms. typed 1tab2tab3tab4tab5tab6tab7tab8tab9tab0. can see, digits queued tab presses dropped.
import java.awt.*; import java.awt.event.*; import java.text.dateformat; import java.text.simpledateformat; import java.util.arraylist; import java.util.date; import java.util.logging.*; import javax.swing.*; import javax.swing.grouplayout.group; import javax.swing.event.documentevent; import javax.swing.event.documentlistener; public class awteventlistenerdemo { public static final logger logger = logger.getlogger(awteventlistenerdemo.class.getname()); private static string keyeventtostring(keyevent keyevent) { int id = keyevent.getid(); string eventname = id == keyevent.key_pressed ? "key_pressed" : id == keyevent.key_typed ? "key_typed" : id == keyevent.key_released? "key_released" : "unknown " + id; string = id == keyevent.key_typed ? "" + keyevent.getkeychar() : "#" + keyevent.getkeycode(); string componentstring = keyevent.getcomponent().getname(); if (componentstring == null) componentstring = keyevent.getcomponent().tostring(); return string.format("%12s %4s on %s", eventname, what, componentstring); } private static string focuseventtostring(focusevent focusevent) { int id = focusevent.getid(); string eventname = id == focusevent.focus_gained ? "focus_gained" : id == focusevent.focus_lost ? "focus_lost" : null; if (eventname == null) return focusevent.tostring(); string componentstring = focusevent.getcomponent().getname(); if (componentstring == null) componentstring = focusevent.getcomponent().tostring(); return string.format("%12s on %s", eventname, componentstring); } private final awteventlistener logginglistener = new awteventlistener() { @override public void eventdispatched(awtevent event) { if (event instanceof keyevent) { keyevent keyevent = (keyevent) event; int id = keyevent.getid(); if (id == keyevent.key_pressed && keyevent.getcomponent() instanceof jtextfield && ((jtextfield)keyevent.getcomponent()).getdocument().getlength() == 1) { eventqueue eventqueue = toolkit.getdefaulttoolkit().getsystemeventqueue(); arraylist<awtevent> inqueue = new arraylist<awtevent>(); int[] interestingids = new int[] {keyevent.key_pressed, keyevent.key_typed, keyevent.key_released, focusevent.focus_gained, focusevent.focus_lost}; (int i: interestingids) { awtevent peek = eventqueue.peekevent(i); if (peek != null) inqueue.add(peek); } arraylist<string> inqueuestring = new arraylist<string>(); (awtevent peek: inqueue) { if (peek instanceof keyevent) { inqueuestring.add(keyeventtostring((keyevent) peek)); } else if (peek instanceof focusevent) { inqueuestring.add(focuseventtostring((focusevent) peek)); } } logger.info(string.format("still in queue (in no particular order): %s", inqueuestring)); } logger.info(keyeventtostring(keyevent)); } else { logger.info(event.tostring()); } } }; private jframe jframe; public void init() { long mask = awtevent.key_event_mask; // awtevent.mouse_event_mask | toolkit.getdefaulttoolkit().addawteventlistener(logginglistener, mask); if (jframe == null) jframe = new jframe(awteventlistenerdemo.class.getsimplename()); swingutilities.invokelater(new runnable() { @override public void run() { initui(); } }); } public void cleanupforrestart() { toolkit.getdefaulttoolkit().removeawteventlistener(logginglistener); } public void destroy() { cleanupforrestart(); jframe.setvisible(false); jframe = null; } public void initui() { grouplayout grouplayout = new grouplayout(jframe.getcontentpane()); jframe.getcontentpane().removeall(); jframe.getcontentpane().setlayout(grouplayout); jbutton jbutton = new jbutton(new abstractaction("restart") { private static final long serialversionuid = 1l; @override public void actionperformed(actionevent e) { cleanupforrestart(); init(); } }); grouplayout.setautocreategaps(true); grouplayout.setautocreatecontainergaps(true); group verticalgroup = grouplayout.createsequentialgroup() .addcomponent(jbutton); group horizontalgroup = grouplayout.createparallelgroup() .addcomponent(jbutton); grouplayout.setverticalgroup(verticalgroup); grouplayout.sethorizontalgroup(horizontalgroup); (int = 0; < 10; i++) { final jtextfield jtextfield = new jtextfield(); jtextfield.setname(string.format("jtextfield %d", i)); verticalgroup.addcomponent(jtextfield); horizontalgroup.addcomponent(jtextfield); boolean usedocumentlistener = true; final boolean usefocusrootancestor = false; if (usedocumentlistener) { documentlistener listener = new documentlistener() { @override public void removeupdate(documentevent e) { } @override public void insertupdate(documentevent e) { // simulate slow event listener. when listener // slow, problems worse. try { thread.sleep(50); } catch (interruptedexception e1) { logger.warning(e1.tostring()); } if (e.getdocument().getlength() > 0) { // these 2 methods of transferring focus appear // equivalent. if (usefocusrootancestor) { container focusroot = jtextfield.getfocuscyclerootancestor(); focustraversalpolicy policy = focusroot.getfocustraversalpolicy(); component nextcomponent = policy.getcomponentafter(focusroot, jtextfield); nextcomponent.requestfocusinwindow(); } else { keyboardfocusmanager.getcurrentkeyboardfocusmanager().focusnextcomponent(jtextfield); } } } @override public void changedupdate(documentevent e) { } }; jtextfield.getdocument().adddocumentlistener(listener); } } if (!jframe.isvisible()) { jframe.pack(); jframe.setdefaultcloseoperation(windowconstants.dispose_on_close); jframe.setvisible(true); } } public static void main(string[] argv) { // use single-line console log handler. logmanager.getlogmanager().reset(); formatter formatter = new formatter() { private simpledateformat dateformat = new simpledateformat("kk:mm:ss.sss"); @override public string format(logrecord logrecord) { date date = new date(logrecord.getmillis()); dateformat.gettimeinstance().format(date); return string.format("%s %s %s %s%n", dateformat.format(date), logrecord.getloggername(), logrecord.getlevel(), logrecord.getmessage()); } }; consolehandler consolehandler = new consolehandler(); consolehandler.setformatter(formatter); consolehandler.setlevel(level.finest); logger.addhandler(consolehandler); logger focuslogger = logger.getlogger("java.awt.focus.defaultkeyboardfocusmanager"); focuslogger.setlevel(level.finest); focuslogger.addhandler(consolehandler); final awteventlistenerdemo demo = new awteventlistenerdemo(); demo.init(); } }
yes, focus
pretty asynchronous, should wrapped int invokelater, no way
edit
import javax.swing.*; import java.awt.*; import java.awt.event.*; //http://www.coderanch.com/t/342205/gui/java/tab-order-swing-components public class testing { private static final long serialversionuid = 1l; private component[] focuslist; private int focusnumber = 0; private jframe frame; public testing() { jtextfield tf1 = new jtextfield(5); jtextfield tf2 = new jtextfield(5); jtextfield tf3 = new jtextfield(5); jbutton b1 = new jbutton("b1"); jbutton b2 = new jbutton("b2"); tf2.setenabled(false); focuslist = new component[]{tf1, b1, tf2, b2, tf3}; jpanel panel = new jpanel(new gridlayout(5, 1)); panel.add(tf1); panel.add(b1); panel.add(tf2); panel.add(b2); panel.add(tf3); frame = new jframe(); frame.setfocustraversalpolicy(new myfocustraversalpolicy()); frame.add(panel); frame.pack(); frame.setlocation(150, 100); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.setvisible(true); keyboardfocusmanager.getcurrentkeyboardfocusmanager().addkeyeventdispatcher(new keyeventdispatcher() { public boolean dispatchkeyevent(keyevent ke) { if (ke.getid() == keyevent.key_pressed) { if (ke.getkeycode() == keyevent.vk_tab) { component comp = keyboardfocusmanager.getcurrentkeyboardfocusmanager().getfocusowner(); if (comp.isenabled() == false) { if (ke.isshiftdown()) { keyboardfocusmanager.getcurrentkeyboardfocusmanager().focuspreviouscomponent(); } else { keyboardfocusmanager.getcurrentkeyboardfocusmanager().focusnextcomponent(); } } } } return false; } }); } private class myfocustraversalpolicy extends focustraversalpolicy { public component getcomponentafter(container focuscycleroot, component acomponent) { focusnumber = (focusnumber + 1) % focuslist.length; return focuslist[focusnumber]; } public component getcomponentbefore(container focuscycleroot, component acomponent) { focusnumber = (focuslist.length + focusnumber - 1) % focuslist.length; return focuslist[focusnumber]; } public component getdefaultcomponent(container focuscycleroot) { return focuslist[0]; } public component getlastcomponent(container focuscycleroot) { return focuslist[focuslist.length - 1]; } public component getfirstcomponent(container focuscycleroot) { return focuslist[0]; } } public static void main(string[] args) { swingutilities.invokelater(new runnable() { @override public void run() { testing testing = new testing(); } }); } }
Comments
Post a Comment