For those interested in my KeyPressed problem - recall that I had a plugin which worked perfectly in most environments, but failed in others. When I set up a new laptop, it turned out to always fail - so I had the opportunity to experiment with it.
I still don't understand everything - but here are the things I changed. Some of them seem like good ideas in general, and others just seem to work and I haven't done enough testing to nail down why. But...the code works perfectly on the new laptop. I'll clean it up and test it on other machines...tomorrow. a) Instead of removing IJ.instance as a KeyListener from ImageWindow and ImageCanvas, I now get the complete list of KeyListeners and remove them all. When done, I will add them all back again. This probably was NOT the problem (because the list seems to be of length 1 - but it's cleaner code than in the KeyListener example on the IJ website. b) Instead of keyPressed(), I now pay attention only to keyTyped(). Someone or something convinced me that keyTyped() was more "reliable". Since it now works with keyTyped, and that code seems simpler - I'm leaving it that way. Again - this is mostly a clean up and may not be relevant to the fix. c) I now do a win.requestFocus *immediately* before waiting for a keyTyped() event. I think this may be the key - the behavior when broken was what you would expect if the ImageWindow had lost focus. I don't really understand how the focus mechanism works, and have been coding by copying for years. d) UNCLEAR at the moment....it's possible that this code fails: win.requestFocus(); keyTyped = false; // set to true by keyTyped() while(!keyTyped) ; // I took out both wait/notify and even Thread.sleep(100) to simplify // key has been typed Note: I'm not really sure this is broken - I may have changed something else. But, the current code is: keyTyped = false; // set to true by keyTyped() while(!keyTyped) win.requestFocus(); // key has been typed This is a bit nasty for a user who wants to interrupt what he's doing and look at another window - I will experiment and try to remove this...tomorrow. I'm reporting at this stage because a few people were very helpful and I'm hoping this jogs someone's memory. I think the issue is FOCUS. The previous version did a win.requestFocus() a bit earlier in the code, and there was enough stuff inbetween that *might* have broken things. But, again, I don't understand FOCUS, so I don't understand why the earlier code fails and this works. My immediate plan is: a) polish the working code so that all the details are taken care of, and it works perfectly. b) experiment with changes, with the goal of breaking it again. c) along the way, I'll probably add back a wait/notify to replace the ugly busy wait - partly to see if either breaks anything, but mostly to repair the ugliness. If I succeed, I'll report back. Thanks again to those who helped, and gave me things to think about. It was VERY helpful! -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
For experts only!
Java plugin Brand new MacBookPro, current OS Built using ‘ant’ The plugin establishes an ImageWindow, on which it periodically updates an Overlay. It is registered as a KeyListener (both ImageWindow and ImageCanvas) QUESTION: is this really necessary? I copied it from the example on the IJ website, but I confess I don’t understand this. All previously registered KeyListeners are removed (and remembered…and re-installed when we are done). Here is the KeyListener code, keyChar and keyTyped are global: // handle keyboard interaction private char keyChar; private boolean keyTyped = false; @Override public void keyTyped(KeyEvent e) { keyChar = e.getKeyChar(); keyTyped = true; } @Override public void keyReleased(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) {} Below is the code to wait for user input and deal with it. I welcome all (expert) opinions on the observed behavior. The cases that do not work puzzle me greatly. Notethat the last option appears to work perfectly as desired - but I don’t understand why. I apologize for not providing a fully working, but minimal plugin. I may try to do this (once I get the working version to the client!). If you are interested, I can send the source code (warning, there is a second piece of source code for a helper Class - if necessary, I can make available the entire ‘ant’ project (and I’d welcome comment I on *that*, too). Actually - I can easily comment out the requirement for the helper Class to reduce this to a single .java file. Perhaps tomorrow, I’ll start taking things out and making this as tiny as possible (while still demonstrating the behavior). I’m *really* puzzled by the fact that the last option works perfectly - I don’t understand why the user CAN interactively switch focus and have that switch stick. I *like* it - but I don’t understand it! … code to update Overlay … ipl.updateAndDraw(); // I include this because it *might* matter while(true) { keyTyped = false; // global variable, set to true by keyTyped() /* This code does NOT work - keyTyped() is not called win.requestFocus(); while(!keyTyped) Thread.sleep(100); */ /* This code does NOT work - keyTyped() is not called win.requestFocus(); while(!keyTyped) ; */ /* This code works, but can't switch focus away from window The focus immediately switches back to our ImageWindow while(!keyTyped) { win.requestFocus(); Thread.sleep(100) } */ /* This code works, and allows the user to switch focus interactively Switching away from our ImageWindow works, is sticky, and no keyTyped() calls Switching back to our ImageWindow works, and KeyTyped() calls happen */ while(!keyTyped) win.requestFocus(); // keyChar is current … code to process keyChar … } -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Greetings,
I'm not expert but... for(Component c : new Component[]{imp,ic}) c.addFocusListener(new FocusListener() { @Override focusGained(FocusEvent e) { IJ.log("Gained: "+e.getSource() +"\n"+e.getComponent() +"\n"+e.getOppositeComponent()); } @Override focusLost(FocusEvent e) { IJ.log("Lost: "+e.getSource() +"\n"+e.getComponent() +"\n"+e.getOppositeComponent()); } }); just a guess... The requestFocus() is only a request and does not guarantee a change in focus, and, probably only tries to fulfill the request the first time after a thread gains control of cpu. Thread.sleep() upon entering gives up control, (even if nothing else tries to take control), and retakes control upon leaving, clearing the fact that the thread had previously request focus. The first two only request the focus once, and if something is stealing focus then it is never requested back. The third is stealing the focus every 100ms. The forth is stealing the focus after something else is done with it, i.e, something else steals the thread control and then when your thread regains it automatically the request focus flag is cleared... Enjoy, Fred On Fri, April 10, 2020 6:19 am, Kenneth Sloan wrote: > For experts only! > > Java plugin > Brand new MacBookPro, current OS > Built using âantâ > > The plugin establishes an ImageWindow, on which it periodically updates an > Overlay. > > It is registered as a KeyListener (both ImageWindow and ImageCanvas) > QUESTION: is this really necessary? I copied it from the example on the > IJ website, but I confess I donât understand this. > > All previously registered KeyListeners are removed (and rememberedâ¦and > re-installed when we are done). > > Here is the KeyListener code, keyChar and keyTyped are global: > > // handle keyboard interaction > private char keyChar; > private boolean keyTyped = false; > @Override > public void keyTyped(KeyEvent e) > { > keyChar = e.getKeyChar(); > keyTyped = true; > } > @Override > public void keyReleased(KeyEvent e) {} > @Override > public void keyPressed(KeyEvent e) {} > > Below is the code to wait for user input and deal with it. I welcome all > (expert) opinions on the observed behavior. The cases that do not work > puzzle me greatly. Notethat the last option appears to work perfectly as > desired - but I donât understand why. > > I apologize for not providing a fully working, but minimal plugin. I may > try to do this (once I get the working version to the client!). If you > are interested, I can send the source code (warning, there is a second > piece of source code for a helper Class - if necessary, I can make > available the entire âantâ project (and Iâd welcome comment I on > *that*, too). Actually - I can easily comment out the requirement for the > helper Class to reduce this to a single .java file. > > Perhaps tomorrow, Iâll start taking things out and making this as tiny > as possible (while still demonstrating the behavior). > > Iâm *really* puzzled by the fact that the last option works perfectly - > I donât understand why the user CAN interactively switch focus and have > that switch stick. I *like* it - but I donât understand it! > > ⦠code to update Overlay ⦠> ipl.updateAndDraw(); // I include this because it *might* matter > > while(true) > { > keyTyped = false; // global variable, set to true by keyTyped() > > /* > This code does NOT work - keyTyped() is not called > win.requestFocus(); > while(!keyTyped) Thread.sleep(100); > */ > > /* > This code does NOT work - keyTyped() is not called > win.requestFocus(); > while(!keyTyped) ; > */ > > /* > This code works, but can't switch focus away from window > The focus immediately switches back to our ImageWindow > while(!keyTyped) > { > win.requestFocus(); > Thread.sleep(100) > } > */ > > /* > This code works, and allows the user to switch focus interactively > Switching away from our ImageWindow works, is sticky, and no > keyTyped() calls > Switching back to our ImageWindow works, and KeyTyped() calls happen > */ > while(!keyTyped) win.requestFocus(); > > // keyChar is current > ⦠code to process keyChar ⦠> } > > -- > Kenneth Sloan > [hidden email] > Vision is the art of seeing what is invisible to others. > > -- > ImageJ mailing list: http://imagej.nih.gov/ij/list.html > -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Thanks. Sounds plausible, and doesn't encourage me to change the code from what works, empirically.
I wonder...do you think this might be an "improvement"? while(!keyTyped) { Thread.sleep(100); win.requestFocus(); } That is - request the focus AFTER sleeping rather than before? but, you know, ugly as a bare busy-wait is, there's not usually much for the computer to do while waiting for human input. Back in the stone ages, where there was ONE CPU and it was THE scarce resource, this mattered. Today, with multi-core machines, who cares? There's still the mystery as to why the original (very naive) code works perfectly on so many machines, fails only intermittently on 2, and fails every time on 1 (of those tested). I'm reminded of an ancient example: some friends were demonstrating new software on a very new processor at a big computer exhibition (ca. 1968). Their code had a bug, but they could *prove* from the listing that the bug was impossible. The only way to explain the behavior was that a "write" instruction was not having any effect. In desperation they changed: write addr, constant to write addr, constant write addr, constant and it worked perfectly. 5 minutes before the doors opened. My working code looks a bit like this. "give me focus, give me focus(no, really), give me focus(damn you!)...". The good news is that the client (I'm sorry: "esteemed colleague") is now picking nits about how the cursors look and how to set the initial parameters, and... all stuff that can be fixed in my sleep. -- Kenneth Sloan [hidden email] Vision is the art of seeing what is invisible to others. -- ImageJ mailing list: http://imagej.nih.gov/ij/list.html |
Free forum by Nabble | Edit this page |