I want to make a Java swing button 'not-focussable'.
The button should not receive focus at all, but should be able to receive mouse clicks.
I thought the following options, but these either dont solve my problem completely, or dont seem elegant. Are there any other/better/suggested options?
Move the focus to the next component immediately when the button receives focus (but then what do I do if the button is the only component on the UI other than labels?)
Implement another non-focusable component as a button (a label with mouse events, borders...) (this does not look very elegant to me)
Create a anonymous button implementation that overides the keyboard events so that it does not respond to keyboard events (this does not solve the focus problem, but is somwhat ok for me, since the root of the problem is to avoid accidental keyboard clicks. I will do this only if there are no options at all, but even then prefer option 2)
All Swing components have a setFocusable method to do this:
JButton button = ...
button.setFocusable(false);
Did you try to call the setFocusable() method inherited from java.awt.Component ?
Resources :
Javadoc - Component.isFocusable()
Oracle.com - Focus tutorial
You can implement your own FocusTraversalPolicy (or extend e.g. ContainerOrderFocusTraversalPolicy) with an accept method that just doesn't like your button.
JFrame frame = new JFrame();
... /* create other components */
frame.setFocusTraversalPolicy(new ContainerOrderFocusTraversalPolicy() {
public boolean accept(Component c) {
return super.accept(c) && c!=iDontLikeYouButton;
}
});
Related
I have searched for this problem and haven't found anything close. I will try to be specific and post code however this is a large program so I can't post all the code. The problem in general is this: A JButton on one panel causes components on another panel to shift at first click. This only occurs when there is an action listener added to the button. (clicking the button without an action listener doe noting (obviously)). The problem is that the action listener i add only changes the button background, text, and size (to fit new text).
Here is the action listener as of right now. login is the JButton:
private class LoginListener implements ActionListener{
public void actionPerformed(ActionEvent e){
loggedIn = !loggedIn;
if(loggedIn){
login.setText("Logout");
login.setBackground(Constants.RED);
}
else{
login.setText("Login");
login.setBackground(Constants.UPPER_BOUNDARY);
}
login.setSize(login.getPreferredSize());
}
}
The setup is this. The action listener is a subclass of the loginPanel where the login button is located. That loginPanel is added to the main JFrame at the upper 1/4 of the frame. The lower 3/4 of the main JFrame is mainPanel which has other swing components. The loginPanel and mainPanel do not share components or variables or really know of each other's existence (as far as I have coded). Yet when this actionlistener above is added to the login button components in the mainPanel shift from their positions to other positions. The only happens at first click and then they stay where they are at (not where i want them).
Other factors:
- I use absolute positioning (sorry if you don't like it but I like it better)
- I am using a SynthLookAndFeel but have never had this issue with this look and feel before.
Thanks
Other factors: - I use absolute positioning (sorry if you don't like it but I like it better)
There's nothing to be sorry about, and the solution is simple: Don't use absolute positioning, but instead learn about and use the layout managers to there full abilities. One of the reasons to use them is to avoid pernicious bugs like this one. It's quite possible that your code is in fact using a component's default layout manager even now without you knowing about it. You can find out more about them here. One of the keys to using them well is to nest them by using nested JPanels, each using its own layout manager. Then they can do the heavy layout lifting for you automatically.
I've been struggling with some problem while creating my app based on Swing. I have a main JFrame which consists of:
JMenu
JPanel containing a JButton and a JLabel
JButton is linked with ActionListener. Clicking JMenu (MenuListener) brings up a JDialog with some form. The problem is, when the JDialog is closed (it doesn't make difference whether I do it with dispose() or rather showVisible(false)) I need to click the JButton two times before it triggers for the first time. From now it normally works with one click.
Every time the JDialog is in front, the problem appears.
PS. The JDialog is set to be modal, with JFrame as parent.
It sounds like a focus issue.
The first click restores focus to the app and the second clicks the button. Typically, I have seen this when the JDialog has the wrong parent and focus can not be returned.
Thank you for your answers.
I have considered posting some code, but it involves 4 classes so will be quite long.
I have also tried things with focus before, but nothing helped. What is interesting: if I display the JDialog by new myDialog.showVisible(true) it behaves like I've described. But if I use construction like this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JDialog.setVisible(true);
}
});
it closes normally and parent frame doesn't need to be clicked before responding, but on the other hand the displayed Dialog needs so. Additonally, what I do not understand, after opening the Dialog cursor is placed in the text field and I can write normally, but to click some button on it I must click once on the Dialog, only second and next clicks behave like I want to.
PS. Closing the dialog like in the second included example changes nothing.
I've created a simple Swing panel that, when loaded, takes up my application's entire window. It contains two JTextAreas and a handful of buttons. I want one of the text areas to have the focus when the panel loads, so that the user can immediately start typing instead of having to click on the text area first. How can I achieve this?
By default focus goes to the first component defined on the window.
If this is not the component you want to have focus then you need to request focus once the window is realized.
The Dialog Focus example shows a couple of ways to do this.
See here the Documentation which contains exactlly what you are searching for (I think):
A component can also be given the
focus programmatically, such as when
its containing frame or dialog-box is
made visible. This code snippet shows
how to give a particular component the
focus every time the window gains the
focus:
//Make textField get the focus whenever frame is activated.
frame.addWindowFocusListener(new WindowAdapter() {
public void windowGainedFocus(WindowEvent e) {
textField.requestFocusInWindow();
}
});
You just need to call requestFocus method of Jcomponent class,
public void requestFocus()
On the Component that you want to focus.
And pleas make sure that you call this method after setVisible is called for its parent component.
For example:-
You have a Jframe in which you added a JTextArea, so after calling you should call in following order:-
jframe.setVisible(true);
jarea.requestFocus();
I have a swing frame that contains embedded panels that contain other panels, etc.
Deep down, there is a button. I want the button to get focus so that pressing the "enter" key would generate an actionPerformed event.
However, if I do myButton.requestFocus() or myButton.requestFocusInWindow() the whole window gets the focus, but nothing seems to happen in terms of keyboard.
I'm obviously missing something about the focus subsystem.
Update2: I explicitly added a KeyListener in addition to the ActionListener and now it works. This is really weird, since I thought that actionListener includes both key and mouse actions.
For the enter key to work you probably want to set the default button rather than the keyboard focus:
button.getRootPane().setDefaultButton(button);
If you really want the keyboard focus then your problem might be related to when you call requestFocus. Sometimes if it is called before a component is fully visible it can be ignored. To fix that you can delay the requestFocus call until after other events have been processed:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
button.requestFocus();
}
});
Sounds like requestFocus() is failing at some level. Try testing to see if any of the parent jPanels or other components can request focus, and work your way up to find out where the problem lies.
There is a way to programatically specify the functionality of the tab ( you know when you press tab and the next widget gets selected )
By default it follows the way the components were added.
Using this custom mechanism will let you select your nested button as the first which receive the actionperformed event.
Unfortunately I don't remember what the name for this "mechanism" is, but is something like traversal or focus traversal
First, don't use requestFocus() use requestFocusInWindow(). requestFocus has platform specific issues, while requestFocusInWindow is more consistent.
Your actual problem; the component (or one of its parents) is probably not visible, or has been render non-focusable.
I want the button to get focus so that
pressing the "enter" key would
generate an actionPerformed event.
The is LAF dependents. Enter works in Windows, but not the Metal LAF. Check out Enter Key and Button for more inforation.
The requestFocusInWindow() method only works if the Component is currently visible on the frame. There are no other tricks so we are just making random guesses about what your are doing wrong. If you need further help you need to post a SSCCE demonstrating the problem.
You can get the rootPane of the frame and update the inputMap and actionMap. See the below code.
InputMap map = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
map.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ok");
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put("ok", enterAction);
Here enterAction is a AbstractAction object whose actionPerformed() will be called when user presses Enter.
I am trying to remove the drag bar across the top of the JFrame. I would like to keep the minimize maximize and close options that appear on this bar available. What I was thinking was to remove the bar (and icons). Then add the icons as embedded images, that implement the JFrame actionlistener. It would also be necessary for this to work with JInternalFrames. Any help would be greatly appreciated.
You need to step back and understand how Swing works.
When you create a JFrame, Swing uses the OS widget for the frame. The title bar that you see is part of the OS component and you have no direct control over it with Swing. You can hide the titlebar (and border) of the frame by using setUndecorated(false) as suggested earlier. In this case you loose all the functionality associated with the title bar (dragging and access to all the buttons) and the Border (resizing). So if you need any of this functionality you need to recreate it all yourself.
On the other hand you can use:
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
and Swing will build a title bar and Border for you and add back all the default functionality. So if you want to prevent dragging you would now need to inspect the JFrame for all its components to find the component that represent the title bar. When you find this component you can then remove the MouseMotionListeners from the component to prevent dragging. This way the title bar will still be there and the buttons will be active, but the dragging will be disabled. I would guess that is easier the adding in all the functionality to an undecorated frame.
As you have already realized a JInternalFrame is a component completely written in Swing so you have access to the child components, which is essentially the approach I'm suggesting for the JFrame as well.
To remove the titlebar, use
setUndecorated(true);
You could then re-add buttons for maximize/minimize. The source for maximize-button could look something like that (just to get an idea). Use JFrame.ICONIFIED for minimize button.
JButton btnMaximize = new JButton("+");
btnMaximize.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(MainFrame.this.getExtendedState() == JFrame.MAXIMIZED_BOTH) {
MainFrame.this.setExtendedState(JFrame.NORMAL);
}
else {
MainFrame.this.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
});
Take a look at this article - i think it is pretty much what you need for the JFrame part.
http://www.stupidjavatricks.com/?p=4
It is based on JDialog, but it should be pretty much the same as JFrame. Maximize/minimize should be pretty much the same as the close button.
For JInternalFrames...
javax.swing.plaf.InternalFrameUI ifu= this.getUI();
((javax.swing.plaf.basic.BasicInternalFrameUI)ifu).setNorthPane(null);