I found this code in several forums to close a frame on ESC keypress. But, I am confused reagrding where to put this peice of code
KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action action = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
jDesktopPane1.getSelectedFrame().dispose();
}
};
jDesktopPane1.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
escape,"escape");
jDesktopPane1.getActionMap().put("escape", action);
Any help will be appreciated.
Wherever you initialize jDesktopPane1, you can put it right after that and it will bind it to it. If there is an init() method for your pane, put it in there so that it gets bound.
We must add a key listener to the java component like frame. Or in your case jdesktoppane.
For an example frame's constructor,
this.addKeyAdapter(
new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyChar()==VK_ESCAPE)
this.dispose();
}
});
Related
I am trying to call a function when a user clicks (with the mouse) on an item in a JComboBox; however, I don't want this event fired for any keyboard events - I only want this fired for a click on a particular cell of the dropdown (I know about addActionListener and addItemListener, but these are fired for more events than I want).
EDIT: I should have specified that mouseClicked doesn't work either - no events seem to be fired (however, they were at one point but when that happened, they fired for clicks on the text field as well), but I thought that was assumed from the title.
I have also tried the solution given here (also doesn't work): Editable JCombobox mouseclicked event not working
EDIT2: I tried the following, but still no output on click:
try {
Field popupInBasicComboBoxUI = BasicComboBoxUI.class.getDeclaredField("popup");
popupInBasicComboBoxUI.setAccessible(true);
BasicComboPopup popup = (BasicComboPopup)popupInBasicComboBoxUI.get(attachedCB.getUI());
Field scrollerInBasicComboPopup = BasicComboPopup.class.getDeclaredField("scroller");
scrollerInBasicComboPopup.setAccessible(true);
JScrollPane scroller = (JScrollPane)scrollerInBasicComboPopup.get(popup);
scroller.getViewport().getView().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
System.out.println("nope");
}
});
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (NoSuchFieldException e) {
e.printStackTrace();
}
You missed adding it to the scrollPane's viewport view in the link I posted in the comments.
Field scrollerInBasicComboPopup = BasicComboPopup.class.getDeclaredField("scroller");
scrollerInBasicComboPopup.setAccessible(true);
JScrollPane scroller = (JScrollPane) scrollerInBasicComboPopup.get(popup);
scroller.getViewport().getView().addMouseListener(listener);
Hope this helps,
jComboBox.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jComboBoxMouseClicked(evt);//your logic here
}
});
You should use java.awt.event.ActionEvent, which is (quoted from javadoc) a
semantic event which indicates that a component-defined action
occurred. This high-level event is generated by a component (such as a
Button) when the component-specific action occurs (such as being
pressed)...
like this:
jComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
javax.swing.JComboBox source = (javax.swing.JComboBox)evt.getSource();
// use getSelectedIndex to know the item if needed
labelTextField.setText(source.getSelectedItem().toString());
}
});
Note getSelectedItem and getSelectedIndex and getSelectedObjects methods : this allows you to know which item has been selected and process only the items you want
I am Trying to make the program respond when the button ESC is clicked so that it will dispose the jframe. I am Not sure what the problem is but it seems to be in the if statement in the main menu.
*Note: te is the object name for the class (Text Editor)
This part is in the main method
f.add(text);
f.addKeyListener(te);
f.setVisible(true);
while(true){
if (exiting == true){
f.dispose();
}
}
This part is outside the main method
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE){
exiting = true;
}
}
Don't use KeyListeners, as a general rule, the component they are attached MUST have key board focus in order to be triggered.
Instead, use a key binding...
InputMap im = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getRootPane().getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
am.put("cancel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
See How to Use Key Bindings for more details
Because of the power of the Action API, I would create a basic "dispose" action to start with:
public class DisposeWindowAction extends AbstractAction {
private Window window;
public DisposeWindowAction(Window window) {
this.window = window;
putValue(NAME, "Dispose");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0));
}
public Window getWindow() {
return window;
}
#Override
public void actionPerformed(ActionEvent e) {
getWindow().dispose();
}
}
I'd then bind this to the ActionMap...
am.put("cancel", new DisposeWindowAction(this));
Why you ask? Because you can then use the same Action in JMenuItems and JButtons`....
JButton disposeButton = new JButton(new DisposeWindowAction(this));
...
(You can use the same instance of the Action, but you get the idea) and now the user has something like three more ways to dispose of the window...
See How to Use Actions for more details
there is an easier way to add a listener to the jframe. All you have to do is create a keylistener overriding keypressed and then check what type of object e.getComponent() is. If it is a window type you can call dispose on it when the escape key is pressed.
public void keyPressed(KeyEvent e){
If(e.getKeyCode() == KeyEvent.VK_ESCAPE){
If( e.getComponent() instanceof Window){
((Window)e.getComponent()).dispose();
}
}
}
You can of course change window to JFrame, and put the two if statements together.
Also you do not need the while loop.
I need a keylistener to be always 'listening' for the escape key to be pressed, to then exit the program.
I have tried typing addKeyListener(this); in my main constructor (the one with the panel being drawn in) and have used
public void keyPressed( KeyEvent e)
{
int code = e.getKeyCode();
if(code == KeyEvent.VK_ESCAPE)
{
System.exit( 0 );
}
}
I get no errors, but pressing the escape key doesn't seem to do anything, any suggestions?
Top-Level Container by default never receiving KeyEvent from KeyListener, by default, but is possible with a few code lines, wrong idea, wrong listener
JPanel by defaul react to KeyEvent, but only in the case that isFocusable, is FocusOwner, wrong idea, wrong listener, (for example) because you needed to move Focus from JTextField to JPanel programatically, wrong idea
add KeyBindings to JFrame/ JDialog / JWindow, accesible by default for Swing JComponent, not for AWT Components
You can use the InputMap/ActionMap mechanism :
Object escapeActionKey = new Object();
pnl.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), escapeActionKey);
pnl.getActionMap().put(escapeActionKey, new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.err.println("escape 1");
}
});
JComponent.WHEN_IN_FOCUSED_WINDOW means that this keystroke is available when the pnl component is in the focused window.
Or you can also add a global AWTEventListener listener :
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
public void eventDispatched(AWTEvent event) {
if(event.getID() == KeyEvent.KEY_PRESSED) {
KeyEvent kEvent = (KeyEvent) event;
boolean isEsc = (kEvent.getKeyCode() == KeyEvent.VK_ESCAPE);
if(isEsc) {
System.err.println("escape 2");
}
}
}
}, AWTEvent.KEY_EVENT_MASK);
In Swing there is a top layer panel : the GlassPane which allow to handle event at top level (to avoid other widget to comsume the event)
I have this code that makes some action execute when user is in textArea (JTextArea instance) and 'enter' is pressed:
textArea.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), actionMapKey);
textArea.getActionMap().put(actionMapKey, new AbstractAction() {
int numLines, lineStart, lineEnd;
Element lineElem;
String lineText;
#Override
public void actionPerformed(ActionEvent e) {
//all the things to be done when enter is pressed
}
});
It works fine, but after the action is handled, no newline appears in the textArea.
Is there any way to pass the 'enter' keystroke on so that it actually creates newline?
Thanks
If I'm not mistaken, you should be able to call the super method you are overloading after all of your custom actions.
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.