I'm trying to develop something like a remote desktop / VNC client. It's necessary for me to capture all events in the client window. The method I'm using is to override the processEvent method of the JFrame:
#Override
protected void processEvent(AWTEvent e) {
...
}
However on events like the Windows key or Alt+Tab the window is getting deactivated:
...
00000191 KEY_PRESSED,keyCode=524,keyText=Windows,keyChar=Undefined keyChar,keyLocation=KEY_LOCATION_LEFT,rawCode=91,primaryLevelUnicode=0,scancode=91,extendedKeyCode=0x20c
00000192 KEY_RELEASED,keyCode=524,keyText=Windows,keyChar=Undefined keyChar,keyLocation=KEY_LOCATION_LEFT,rawCode=91,primaryLevelUnicode=0,scancode=91,extendedKeyCode=0x20c
000000ce WINDOW_DEACTIVATED,opposite=null,oldState=0,newState=0
...
How do I keep the window active on such events?
I would prefer a pure Java solution to this. If there is no pure java solution, can someone point me towards a JNA solution (or any other solution for that fact)?
EDIT1:
* Resolved ambiguous term 'focus' to window deactivation
* Emphasized that non pure Java solutions are acceptible
1.) JNA comes with an example that does almost what you want:
http://java.net/projects/jna/sources/svn/content/trunk/jnalib/contrib/w32keyhook/KeyHook.java
In order to block a key, just return 1 instead of calling CallNextHookEx - cf. the MSDN documenttaion.
2.) JNativeHook allows you to hook into global event processing, but right now there is no way of stopping events from being deliverd - e.g. the Windows key will still activate the start menu. However it is still worth looking at since it comes with much less overhead, and you can modify it (starting with CallNextHookEx here) to behave the way you want. It is licensend under the GPL though.
3.) Another clean way of doing this, would be to switch to SWT and use the SWT Win32 Extensions to intercept keyboard events.
Can you not set the window to be focusable all the time (Window.setFocusableWindowState), because JFrame does inherit that method from Window. Something simple like: window.setFocusableWindowsState(true). And inside a key event listener call this:
(this code is modified, but originally from Unresponsive KeyListener for JFrame)
public class MyFrame extends JFrame {
private class MyDispatcher implements KeyEventDispatcher
{
private JFrame frame;
public MyDispatcher(JFrame jf)
{
this.frame = jf;
}
public boolean dispatchKeyEvent(KeyEvent e)
{
frame.setFocusableWindowState(true);
return false;
}
}
public MyFrame()
{
add(new JTextField());
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher(this));
}
public static void main(String[] args)
{
MyFrame f = new MyFrame();
f.pack();
f.setVisible(true);
}
}
I did not get to test this code, but i hope at least the idea is getting you in right direction.
You can set a custom FocusManager and override the dispatchEvent method or use Toolkit.getDefaultToolkit().addAWTEventListener(..). However this won't catch OS-catched keyEvents, but you will still get events like repaint if you register at the toolkit.
You can use WindowListener.Hope this will help to capture the event .There are windowfocuslistener,windowstatelistener too.
public class WindowListenerImpl implements WindowListener(){
#Override
public void windowOpened(WindowEvent windowevent) {
//urs windowevent to get source.
}
#Override
public void windowIconified(WindowEvent windowevent) {
//urs windowevent to get source.
}
#Override
public void windowDeiconified(WindowEvent windowevent) {
//urs windowevent to get source.
}
#Override
public void windowDeactivated(WindowEvent windowevent) {
//urs windowevent to get source.
}
#Override
public void windowClosing(WindowEvent windowevent) {
//urs windowevent to get source.
}
#Override
public void windowClosed(WindowEvent windowevent) {
//urs windowevent to get source.
}
#Override
public void windowActivated(WindowEvent windowevent) {
//urs windowevent to get source.
}
public WindowEvent{
public static void main(String[] args){
WindowListenerImpl listenerImpl=new WindowListenerImpl ();
new JFrame.addWindowListener(listenerImpl);
}
Related
I am creating an application in Java and I would like that when you minimize to an icon, the application will have to "hide" in the system tray.
The code I use is this: (the significant part of the code)
myFrame = new JFrame();
myFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent e) {
PutTray();
}
#Override
public void windowDeiconified(WindowEvent e) {
System.out.println("Deiconified");
}
});
This is a "PutTray" function:
private void PutTray()
{
try
{
tray.add(trayIcon); // Initialized elsewhere
myFrame.setVisible(false);
} catch (AWTException e) {
System.err.println(e);
}
}
To restore (via option in the pop-up menu when you press the icon minimized):
MenuItem show = new MenuItem("Show");
show.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myFrame.setVisible(true);
myFrame.setState(JFrame.NORMAL);
tray.remove(trayIcon);
}
});
The code works perfectly on Windows 8, but it does not work on Linux (Kali Linux and even Ubuntu).
Why Windows yes and Linux no?
EDIT:
On Linux, after you press the command to show the application, it appears for a very small moment, and then minimizes again. Basically is triggered the event "windowDeiconified" and immediately after the event "windowIconified" without taking the time to do something else and then the application is shown in the system tray.
As Dan Getz suggests, I also thought the order of setVisible and setState should be inverted since the javadoc for setState says:
If the frame is not visible on the
* screen, the events may or may not be
* generated.
but this didn't help.
The one thing that did help though was replacing setVisible(false) with dispose(). They are similar in that you can use setVisible(true) to reopen a disposed window. You can read more about it here: JDialog setVisible(false) vs dispose()
I'll try to find an explanation and come back with it :)
SSCCE to simulate OP problem:
public class Test {
private JFrame myFrame;
public Test() {
myFrame = new JFrame();
myFrame.setVisible(true);
myFrame.setSize(300, 300);
myFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent e) {
PutTray();
}
});
}
private void PutTray() {
myFrame.setVisible(false); //replace with dispose(); and it's ok
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
myFrame.setVisible(true);
}
});
t.setRepeats(false);
t.start();
}
public static void main(String[] args) {
new Test();
}
}
I think you are getting it wrong!
Maybe you are confused about deiconified and visibility
windowIconified()
will be called when we click minimize button
and
windowDeiconified()
is called when we restore it from taskbar and not system tray!
In order to restore from system tray you need to use this
trayIcon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
window.setVisible(true);
}
});
Basically i don't think the difference between dispose() & setVisible() will bother you in this specific problem
Still, my recommendation is to use setVisible() here
Right now I am using a MouseListener to see if the mouse is pressed but it doesn't register when you press outside of an JFrame I would really need it to so how do I check for mouse events outside of a JFrame?
Right now I am using a MouseListener to see if the mouse is pressed
but it doesn't register when you press outside of an JFrame I would
really need it to so how do I check for mouse events outside of a
JFrame?
then JFrame lost Focus, you can test by using WindowFocusListener
Focus is asynchronous, then everything inside windowGainedFocus and windowLostFocus should be wrapped into invokeLater
Add a window listener
addWindowListener(new WindowListener() {
#Override
public void windowOpened(WindowEvent arg0) {
}
#Override
public void windowIconified(WindowEvent arg0) {
}
#Override
public void windowDeiconified(WindowEvent arg0) {
}
#Override
public void windowDeactivated(WindowEvent arg0) {
}
#Override
public void windowClosing(WindowEvent arg0) {
}
#Override
public void windowClosed(WindowEvent arg0) {
}
#Override
public void windowActivated(WindowEvent arg0) {
}
});
Try out all the methods (window...) and see which one works out best for you!
:)
I'm not telling you exactly what to do because to learn you cant just copy paste!
To know the status of mouse outside the window you can use:
Point point = MouseInfo.getPointerInfo().getLocation();
Unfortunatly java.awt.event.MouseMotionListener give you information about mouse movement inside your window.
I have 2 classes.
One extends canvas and inside creates a jframe and add the canvas to that jframe and add another keyadapter class to receive key events. I also have main function to test the code. When running from main, the form is displayed and recieves key events too.
Now i create another class that extends jframe and implements keylistener to receive events in this form.
Once the functionality done in the second class i want to close the second form and show the first form. When showing it from the key event functions in the second class the first class key listener is not working.
Please just have a glimpse at my code and tell me how to correct my prob. Thanks for your time and valuable suggestion.
Class 1
public class Test extends Canvas {
private JFrame container;
public Test() {
container = new JFrame("Space Invaders");
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(screenSize.width, screenSize.height));
panel.setLayout(null);
setBounds(0, 0, screenSize.width, screenSize.height);
panel.add(this);
container.pack();
container.setResizable(false);
container.setVisible(true);
try {
addKeyListener(new KeyInputHandler(this));
} catch (Exception e) {
e.printStackTrace();
}
requestFocus();
}
private class KeyInputHandler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
//Some Action
}
public void keyReleased(KeyEvent e) {
//Some Action
}
public void keyTyped(KeyEvent e) {
//Some Action
}
}
public static void main(String args[]){
//Running this canvas here works perfectly with all added keylisteners
}
}
Class 2
public class Sample extends JFrame implements KeyListener {
public Sample() {
init();
this.setSize(100, 100);
this.setVisible(true);
Sample.this.dispose();
// Created a window here and doing some operation and finally redirecting
// to the previous test window. Even now the test window works perfectly
// with all keylisteners
new Test();
}
public static void main(String[] args) {
new Sample();
}
private void init() {
addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
removeKeyListener(this);
Sample.this.dispose();
// But when calling the previous Test window here, the window
// gets displayed but the keylistener is not added to the
// window. No keys are detected in test window.
new Test();
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Simple dont use KeyListener/KeyAdapter that is for AWT components and has known focus issues when used with Swing.
The issues can be got around by making sure your component is focusable via setFocusable(true) and than call requestFocusInWindow() after component has been added/is visible.
Rather use KeyBindings for Swing.
For example say now we wanted to listen for D pressed and released:
public static void addKeyBindings(JComponent jc) {
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "D pressed");
jc.getActionMap().put("D pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("D pressed");
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "D released");
jc.getActionMap().put("D released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("D released");
}
});
}
We would call this method like:
JPanel ourPanel=new JPanel();
...
addKeyBindings(ourPanel);//adds keybindings to the panel
Other suggestions on code
Always create and manipulate Swing components on Event Dispatch Thread, via SwingUtilities.invokeLater(Runnable r) block
Dont extend JFrame class unnecessarily
Dont implement interfaces on a class unless the class will be used for that purpose, or other classes need access to the interfaces methods.
As mentioned by #AndrewThompson, dont use multiple JFrames, either swap the rest for JDialog, or use CardLayout. See here for an example.
I've extended a JList to provide two separate functionalities, toolTipText for items, and right-click options. Both work separately, but when I try to use them together, the MouseMoved events aren't being recognized? Below are the guts of my new listener methods. How should I be negotiating these various events?
public class JListTT extends javax.swing.JList {
public JListTT() {
super();
addMouseListener(new ttListener());
...
class ttListener extends MouseAdapter {
public void mouseMoved(MouseEvent e) {
String nodeID = bldItemNodeID();
theList.setToolTipText(nodeID);
}
public void mousePressed(MouseEvent ev) {check(ev); }
public void mouseReleased(MouseEvent ev) {check(ev); }
public void mouseClicked(MouseEvent ev) {check(ev); }
public void check(MouseEvent ev) {
if (ev.isPopupTrigger()) {
theList.setSelectedIndex(theList.locationToIndex(ev.getPoint()));
menu.show(theList, ev.getX(), ev.getY());
}
}
}
You add the ttListener object as a MouseListener, but I don't see you adding the ttListener object as a MouseMotionListener. For example:
ttListener myMouseadapter = new ttListener();
addMouseListener(myMouseadapter);
addMouseMotionListener(myMouseadapter);
I did not test this myself, but looking at the javadoc of JList the tooltip functionality is available out of the box. The javadoc of JList#getTooltipText clearly states
Overrides JComponent's getToolTipText method in order to allow the
renderer's tips to be used if it has text set.
So if your ListCellRenderer returns a Component in the getListCellRendererComponent method which has a tooltip it will be displayed by the JList without the need of a listener.
there's not necessarily a need for a low-level approach as a custom mouse-/motionListener:
as to a per-cell tooltip, see #Robin's answer
as to a context menu, JComonent has a property componentPopupMenu: using that will cope with opening the menu on keyboard short-cut automatically
"not necessarily" because you seem to rely on the cell being selected on right click. If so, you would still need a MouseListener to trigger the selection (after decade long debates, Swing doesn't - which seems to be unusual in current native apps ;-)
You can achieve it by using mouseDragged
YourClass extends JPanel implements MouseListener{
......
#Override
public void mouseDragged(MouseEvent e) {
//code go here
}
}
Is there a way to close a JDialog through code such that the Window event listeners will still be notified? I've tried just setting visible to false and disposing, but neither seem to do it.
Closing a window (with dispose()) and hiding it (with setVisible(false)) are different operations, and produce different events -- and closing it from the operating system is yet another different operation that produces yet a different event.
All three will produce windowDeactivated to tell you the window's lost focus, but dispose() will then produce windowClosed, while closing from the OS will first produce windowClosing. If you want to handle both of these the same way, you can set the window to be disposed when closed:
window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
In general, setVisible(false) implies that you might want to use the window again, so it doesn't post any window events (apart from windowDeactivated). If you want to detect the hiding of a window, you need to use a ComponentListener;
window.addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("componentHidden()");
}
})
Note though that this will pretty much only work for explicit setVisible() calls. If you need to detect hiding more generally, you can use a HierarchyListener, but it's probably more trouble than it's worth.
window.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("valid: " + window.isValid());
System.out.println("showing: " + window.isShowing());
}
});
Note that when you dispose a window you'll get a couple of HierarchyEvents, first for hiding and then for invalidation, but when you hide it with setVisible() it's still valid, so you won't get the invalidation.
I don't seem to have your problem. When I use the code below windowDeactivated() is called for either setVisible( false ) or dispose() and windowClosed() is also called for dispose().
ClosingDialog.java:
public class ClosingDialog extends JDialog {
public ClosingDialog(Frame owner, String title, boolean modal) {
super(owner, title, modal);
JPanel contentPanel = (JPanel) this.getContentPane();
JButton setVisButton = new JButton("setVisible( false )");
setVisButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ClosingDialog.this.setVisible(false);
}
});
JButton disposeButton = new JButton("dispose()");
disposeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ClosingDialog.this.dispose();
}
});
contentPanel.setLayout(new FlowLayout());
contentPanel.add(setVisButton);
contentPanel.add(disposeButton);
this.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent e) {
System.out.println("windowActivated");
}
public void windowClosed(WindowEvent e) {
System.out.println("windowClosed");
}
public void windowClosing(WindowEvent e) {
System.out.println("windowClosing");
}
public void windowDeactivated(WindowEvent e) {
System.out.println("windowDeactivated");
}
public void windowDeiconified(WindowEvent e) {
System.out.println("windowDeiconified");
}
public void windowIconified(WindowEvent e) {
System.out.println("windowIconified");
}
public void windowOpened(WindowEvent e) {
System.out.println("windowOpened");
}
});
this.setSize(300, 300);
}
}
Dispatch a windowClosing event to the Window. Check out the ExitAction example from the Closing an Application entry.
Untested suggestion:
Have you tried getWindowListeners() and then iterating around to fire windowClosed() to each of the WindowListeners?
EDIT: the above suggestion is wrong. Keeping it for posterity.
I'm afraid calling dialog.dispose() works fine for me in my simple example.
I wanted to fire a windowClosing event from the code (just as if the user clicked the X), because I have an extra close button in the JDialog and want the same WindowListener (that I implemented using a WindowAdapter) to be run when the X is clicked and when the button is clicked. Running dispose() only fires windowClosed, not windowClosing, and I want a message to appear before the window is closed, for confirmation. I also didn't manage to fire windowClosing via JDialog's method processWindowEvent since it is protected.
Here is how I got it working though:
WindowAdapter adapter = (WindowAdapter)jdialog.getWindowListeners()[0];
adapter.windowClosing(new WindowEvent((Window)jdialog, WindowEvent.WINDOW_CLOSING));
Hope that helps someone.