I have a component where i want to display a custom jtooltip. That is easy, just change the getTooltip method. Similar for location and text.
However i also want to change the timers. The tooltip should always be displayed if the mouse is over a cellrenderer of the component. If it leaves all of those it should be turned invisible.
I know that i can use TooltipManager to control the times globally. But the best solution is probably to just shortcircut that and display the tooltip myself with a mouselistener. However when i tried to do that (unregister the component in TooltipManager and setting the tooltip visible, with text and in the correct position, in a mouse listener) the tooltip never showed at all. What am i doing wrong?
Edit:
Now the question has changed! Into 2 questions.
My solution is for now this, however it losses the shadow that the jtooltip always displays sometimes frustratingly, and it is hidden if the mouse exits into the popup itself. How to filter the mouseexit events over the popup if the popup is not even a component? I could do some hacking based on the lastPosition, but that seems stupid, since i don't really know its width.
private Popup lastPopup;
private final JToolTip tooltip = ...;
private Point lastPoint;
#Override public void mouseMoved(MouseEvent e) {
Point p = privateToolTipLocation(e);
if (p == null || p.equals(lastPoint)) {
return;
}
lastPoint = p;
tooltip.setTipText(privateToolTipText(e));
//copy
p = new Point(p);
SwingUtilities.convertPointToScreen(p, this);
Popup newPopup = PopupFactory.getSharedInstance().getPopup(this, tooltip, p.x, p.y);
if (lastPopup != null) {
lastPopup.hide();
}
lastPopup = newPopup;
newPopup.show();
}
#Override public void mouseExited(MouseEvent e) {
if (lastPopup != null && someUnknownCondiction) {
lastPopup.hide();
lastPopup = null;
}
}
Rather than trying to reimplement the display of tooltips, you could add a mouse listener to your component that changes the global tooltip timer when the mouse enters and leaves the region above the component.
Here is some example code:
instantTooltipComponent.addMouseListener(new MouseAdapter()
{
final int defaultTimeout = ToolTipManager.sharedInstance().getInitialDelay();
#Override
public void mouseEntered(MouseEvent e) {
ToolTipManager.sharedInstance().setInitialDelay(0);
}
#Override
public void mouseExited(MouseEvent e) {
ToolTipManager.sharedInstance().setInitialDelay(defaultTimeout);
}
});
This should change the tooltip delay to zero whenever the mouse moves over your component and change it back to the default delay whenever the mouse moves off of your component.
But the best solution is probably to
just shortcircut that and display the
tooltip myself with a mouselistener
Invoke the default Action for the component to display the tooltip:
Action toolTipAction = component.getActionMap().get("postTip");
if (toolTipAction != null)
{
ActionEvent postTip = new ActionEvent(component, ActionEvent.ACTION_PERFORMED, "");
toolTipAction.actionPerformed( postTip );
}
Edit:
Above code doesn't appear to work anymore. Ctrl+F1 is the default KeyStroke used to display the tool tip of a component. So an alternative approach is to dispatch the Ctrl+F1 KeyStroke to the component. For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PostTipSSCCE2 extends JPanel
{
public PostTipSSCCE2()
{
FocusAdapter fa = new FocusAdapter()
{
public void focusGained(FocusEvent e)
{
JComponent component = (JComponent)e.getSource();
KeyEvent ke = new KeyEvent(
component,
KeyEvent.KEY_PRESSED,
System.currentTimeMillis(),
KeyEvent.CTRL_MASK,
KeyEvent.VK_F1,
KeyEvent.CHAR_UNDEFINED);
component.dispatchEvent( ke );
}
};
MouseAdapter ma = new MouseAdapter()
{
#Override
public void mouseEntered(MouseEvent e)
{
JComponent component = (JComponent)e.getSource();
KeyEvent ke = new KeyEvent(
component,
KeyEvent.KEY_PRESSED,
System.currentTimeMillis(),
KeyEvent.CTRL_MASK,
KeyEvent.VK_F1,
KeyEvent.CHAR_UNDEFINED);
component.dispatchEvent( ke );
}
};
JButton button = new JButton("Button");
button.setToolTipText("button tool tip");
button.addFocusListener( fa );
button.addMouseListener( ma );
add( button );
JTextField textField = new JTextField(10);
textField.setToolTipText("text field tool tip");
textField.addFocusListener( fa );
textField.addMouseListener( ma );
add( textField );
JCheckBox checkBox = new JCheckBox("CheckBox");
checkBox.setToolTipText("checkbox tool tip");
checkBox.addFocusListener( fa );
checkBox.addMouseListener( ma );
add( checkBox );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("PostTipSSCCE2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new JScrollPane(new PostTipSSCCE2()) );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Apparently what controls the display of the Tooltip is if the getTooltipText returns null or not. Having that to null, eliminated a npe and allowed things to display. However there are some artifacts still..
Related
I'm creating a form in Java Swing, and one of the fields is a JTextArea. When I use the Tab key on all other fields, it gives the focus to the next widget, but in the JTextArea, it inserts a tab character (horizontal space) in the text.
How can I modify this behavior?
/*
This is my understanding of how tabbing works. The focus manager
recognizes the following default KeyStrokes for tabbing:
forwards: TAB or Ctrl-TAB
backwards: Shift-TAB or Ctrl-Shift-TAB
In the case of JTextArea, TAB and Shift-TAB have been removed from
the defaults which means the KeyStroke is passed to the text area.
The TAB KeyStroke inserts a tab into the Document. Shift-TAB seems
to be ignored.
This example shows different approaches for tabbing out of a JTextArea
Also, a text area is typically added to a scroll pane. So when
tabbing forward the vertical scroll bar would get focus by default.
Each approach shows how to prevent the scrollbar from getting focus.
*/
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
public class TextAreaTab extends JFrame
{
public TextAreaTab()
{
Container contentPane = getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
contentPane.add( nullTraversalKeys() );
contentPane.add( writeYourOwnAction() );
contentPane.add( useKeyListener() );
contentPane.add( addTraversalKeys() );
}
// Reset the text area to use the default tab keys.
// This is probably the best solution.
private JComponent nullTraversalKeys()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Null Traversal Keys\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
// scrollPane.getVerticalScrollBar().setFocusable(false);
textArea.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
textArea.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
return scrollPane;
}
// Replace the Tab Actions. A little more complicated but this is the
// only solution that will place focus on the component, not the
// vertical scroll bar, when tabbing backwards (unless of course you
// have manually prevented the scroll bar from getting focus).
private JComponent writeYourOwnAction()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Write Your Own Tab Actions\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
InputMap im = textArea.getInputMap();
KeyStroke tab = KeyStroke.getKeyStroke("TAB");
textArea.getActionMap().put(im.get(tab), new TabAction(true));
KeyStroke shiftTab = KeyStroke.getKeyStroke("shift TAB");
im.put(shiftTab, shiftTab);
textArea.getActionMap().put(im.get(shiftTab), new TabAction(false));
return scrollPane;
}
// Use a KeyListener
private JComponent useKeyListener()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Use Key Listener\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.getVerticalScrollBar().setFocusable(false);
textArea.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_TAB)
{
e.consume();
KeyboardFocusManager.
getCurrentKeyboardFocusManager().focusNextComponent();
}
if (e.getKeyCode() == KeyEvent.VK_TAB
&& e.isShiftDown())
{
e.consume();
KeyboardFocusManager.
getCurrentKeyboardFocusManager().focusPreviousComponent();
}
}
});
return scrollPane;
}
// Add Tab and Shift-Tab KeyStrokes back as focus traversal keys.
// Seems more complicated then just using null, but at least
// it shows how to add a KeyStroke as a focus traversal key.
private JComponent addTraversalKeys()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Add Traversal Keys\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.getVerticalScrollBar().setFocusable(false);
Set set = new HashSet( textArea.getFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "TAB" ) );
textArea.setFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set );
set = new HashSet( textArea.getFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "shift TAB" ) );
textArea.setFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
return scrollPane;
}
class TabAction extends AbstractAction
{
private boolean forward;
public TabAction(boolean forward)
{
this.forward = forward;
}
public void actionPerformed(ActionEvent e)
{
if (forward)
tabForward();
else
tabBackward();
}
private void tabForward()
{
final KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.focusNextComponent();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (manager.getFocusOwner() instanceof JScrollBar)
manager.focusNextComponent();
}
});
}
private void tabBackward()
{
final KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.focusPreviousComponent();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (manager.getFocusOwner() instanceof JScrollBar)
manager.focusPreviousComponent();
}
});
}
}
public static void main(String[] args)
{
TextAreaTab frame = new TextAreaTab();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
you could use the "NextWidget.grabFocus()" method within keylistener of JTextArea when key "tab" is pressed
With this latter approach the tab character will still get inserted into the JTextArea before the focus is shifted away. If you dont want that behavior you can create a subclass of JTextArea whose isManagingFocus() method always returns false, instead of true. For example:
import javax.swing.*;
public class NoTabTextArea extends JTextArea {
public boolean isManagingFocus() {
return false;
}
}
An instance of NoTabTextArea can be used exactly like a JTextArea, except that the tab key will cause the focus to shift away from it without a tab character being inserted.
You can call the following method in your main JFrame or JPanel constructor.
Use by calling as so: disableTabbingInTextAreas(this)
public static void disableTabbingInTextAreas(Component component){
if(component instanceof Container && !(component instanceof JTextArea)){
for(final Component c : ((Container) component).getComponents() ){
disableTabbingInTextAreas(c);
}
}else if(component instanceof JTextArea){
final Component c = component;
c.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyChar() == '\t'){
c.transferFocus();
e.consume();
}
}
#Override
public void keyReleased(KeyEvent e) {}
});
}
}
import javax.swing.* ;
import java.awt.event.* ;
/**
* This simple subclass of JTextArea does not allow the 'Tab'
* to be pressed. Instead of putting in 3 blank spaces, the tab
* will transfer focus
*/
/*-----------------------------------------------------------*/
/* */
/* NoTabJTextArea */
/* */
/*-----------------------------------------------------------*/
public class NoTabJTextArea extends JTextArea implements KeyListener {
public NoTabJTextArea ( String text ) {
super ( text ) ;
initialize () ;
}
public NoTabJTextArea ( ) {
super() ;
initialize() ;
}
public NoTabJTextArea ( MaskDocument document ) {
super ( document ) ;
initialize() ;
}
private void initialize () {
addKeyListener ( this ) ;
}
public void keyPressed ( KeyEvent e ) {
switch ( e.getKeyCode() ) {
case KeyEvent.VK_TAB :
e.consume() ;
transferFocus() ;
break ;
}
}
public void keyReleased ( KeyEvent e ) {
switch ( e.getKeyCode() ) {
case KeyEvent.VK_TAB :
System.out.println ( "KEY RELEASED TAB" ) ;
break ;
}
}
public void keyTyped ( KeyEvent e ) {
switch ( e.getKeyCode() ) {
case KeyEvent.VK_TAB :
System.out.println ( "KEY TYPED TAB" ) ;
break ;
}
}
} /* NoTabJTextArea */
As isManagingFocus method is deprecated since 1.4, it is also possible to use setFocusTraversalKeys. The example applies the default "on tab" behaviour to the JTextArea field.
import javax.swing.*;
import java.awt.*;
public class NoTabTextArea extends JTextArea {
public NoTabTextArea(String text, int rows, int columns) {
super(text, rows, columns);
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
}
}
I am trying to make this program for minecraft, and now im just getting started. I want that if you click a label, it will check what label is it and will do something.
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me.getX()+", "+me.getY()+".");
Object source = me.getSource();
int intx = me.getX();
int inty = me.getY();
if(me.getX()>=1 && me.getY()>=1 && me.getX()<=70 && me.getY()<=45){
permissionsframe.setLocation(810,250);
System.out.println(p1p.length);
permissionsframe.pack();
permissionsframe.setSize(200, 200);
permissionsframe.setVisible(true);
JLabel playerperms = new JLabel("Player "+p1s+" has "+p1p.length+" permissions.");
playerperms.setBounds(1, 1, 150, 150);
permissionsframe.add(playerperms);
System.out.println("You chose "+player1.getText()+".");
}
else{
System.out.println("You did not click any label.");
}
}
});
This selection area is adapted to the name I have now - NonameSL. But if the name will be longer or shorter, the selection area will obviuosly be different...
Is there a way to get the excact label? I tried if(source.equals(player1))(Player 1 is the label) but I placed the label in 1, 1 and I have to click the excact point that I defined the label in, X=1, Y=1. How can I make a mouse listener listen to a label?
There is no need to check if the mouse coordinates are inside your JLabel.
You can bind a Listener to every JLabel an process the click/press event in your MyMouseListener.class
To do so:
You have to add the MouseListener to every JLabel:
MyMouseListener myMouseListener = new MyMouseListener();
label01.setName("name01");
label01.addMouseListener(myMouseListener);
label02.setName("name02");
label02.addMouseListener(myMouseListener);
To identify the JLabel you could do something like this:
class MyMouseListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
JLabel l = (JLabel) e.getSource();
if(l.getName().equals("name01"))
doSomething01();
else if(l.getName().equals("name02"))
doSomething02();
}
}
The correct way to do this is to use the .getComponent() method instead of the .getSource() since this is MouseEvent which is something different than ActionEvent.
Implement the Listener to your class:
public class Main implements MouseListener {
public static void main(String[] args) {
//setup JFrame and some label and then
label.addMouseListener(this);
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getComponent().equals(label)) {
System.out.println("clicked");
}
}
//the other orderride methods..
I have a JPopupMenu which contains an inner JMenu and a separator with addSeparator(). Due to some odd handling, I've added a MouseListener to the JPopupMenu which makes it invisible on a mouseExited event. This works fine, except that when the mouse tries to cross over the separator, it's triggering the event (even though the JPopupMenu is the super component).
If I remove the addSeparator() line, it works as expected.
Is there any way to work around this? Or have I not set up the listener properly?
The code is like the following:
JPopupMenu popupMenu = new JPopupMenu();
JMenu innerMenu = new JMenu("Inner");
// ... add JMenuItems
popupMenu.add(innerMenu);
popupMenu.addSeparator();
popupMenu.add(new JMenuItem("Exit"));
popupMenu.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
popupMenu.setVisible(false);
}
});
Full Compilable Example
Simply comment and uncomment the popupMenu.addSeparator() line to notice the different behaviors
public class Test {
public static void main(String[] args) throws Exception {
if(!SystemTray.isSupported()) {
throw new UnsupportedOperationException("SystemTray is not supported.");
}
final TrayIcon trayIcon = new TrayIcon(ImageIO.read(new File("resources/icon.gif")));
final JPopupMenu popupMenu = new JPopupMenu();
JMenu intervalMenu = new JMenu("Interval");
ButtonGroup itemGroup = new ButtonGroup();
JRadioButtonMenuItem oneSecondMenuItem = new JRadioButtonMenuItem("1 sec");
itemGroup.add(oneSecondMenuItem);
JRadioButtonMenuItem twoSecondMenuItem = new JRadioButtonMenuItem("2 sec");
itemGroup.add(twoSecondMenuItem);
intervalMenu.add(oneSecondMenuItem);
intervalMenu.add(twoSecondMenuItem);
popupMenu.add(intervalMenu);
popupMenu.addSeparator();
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
SystemTray.getSystemTray().remove(trayIcon);
System.exit(0);
}
});
popupMenu.add(exitMenuItem);
//Thanks to Artem Ananiev for this implementation idea
//https://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html
trayIcon.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON3) {
popupMenu.setLocation(e.getX() - 40, e.getY() - 40);
popupMenu.setInvoker(popupMenu);
popupMenu.setVisible(true);
}
}
});
popupMenu.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
popupMenu.setVisible(false);
}
});
SystemTray.getSystemTray().add(trayIcon);
}
}
Wow, you are using a sytem tray icon. That information might have been important to know. That is why a SSCCE should be posted with EVERY question.
Anyway the following seems to work:
if (! popupMenu.contains( e.getPoint() ) )
popupMenu.setVisible(false);
Edit:
It looks like the problem is that the JSeparator does not listen for MouseEvents by default so all the mouse events are passed to its parent. So when you leave a JMenuItem, the mouseEntered() event is generated for the popup menu and then when you re-enter another JMenuItem the mouseExited() event is generated.
If you enable MouseEvents for the JSeparator then it look like the JPopupMenu doesn't get the event
//popupMenu.addSeparator();
popupMenu.add( new MySeparator() );
...
static class MySeparator extends JSeparator
{
public MySeparator( )
{
super( JSeparator.HORIZONTAL );
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
/**
* Returns the name of the L&F class that renders this component.
*
* #return the string "PopupMenuSeparatorUI"
* #see JComponent#getUIClassID
* #see UIDefaults#getUI
*/
public String getUIClassID()
{
return "PopupMenuSeparatorUI";
}
}
I want to implement a method where the user needs to hold the left and right mouse buttons at the same time.
I'm using Swing and Java 1.7. I've tried this, but it doesn't detect the both-buttons case like I'd expect it to:
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && SwingUtilities.isRightMouseButton(e)){
///code here
}
}
i tried to separate methods and use bool values to decide if the mouse button is pressed and then i set a condition to find out if both of them are pressed at the same time , but that didint work out too ..
This is an SSCCE that does what you want... i.e. if I understood your question correctly.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class StackOverflow15957076 extends MouseAdapter
{
private JLabel status;
private boolean isLeftPressed;
private boolean isRightPressed;
public StackOverflow15957076 ()
{
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel (new FlowLayout (FlowLayout.CENTER));
status = new JLabel ("waiting for both mouse buttons...");
status.addMouseListener (this);
panel.add (status);
frame.add (panel);
frame.pack ();
frame.setVisible (true);
isLeftPressed = false;
isRightPressed = false;
}
#Override
public void mousePressed (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
isLeftPressed = true;
}
else if (SwingUtilities.isRightMouseButton (e))
{
isRightPressed = true;
}
if (isLeftPressed && isRightPressed)
{
status.setText ("both buttons are pressed");
}
}
#Override
public void mouseReleased (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
isLeftPressed = false;
}
else if (SwingUtilities.isRightMouseButton (e))
{
isRightPressed = false;
}
status.setText ("waiting for both mouse buttons...");
}
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
#Override
public void run ()
{
new StackOverflow15957076 ();
}
});
}
}
It seems that it's not possible do it directly, since mouse events are fired sequentially. See, for example, this SO question/answers.
So you will need to decide what "at the same time" actually means to you (i.e. how close in time thay should be). Then you can capture two separate events and compare their getWhen() values.
I'm creating a form in Java Swing, and one of the fields is a JTextArea. When I use the Tab key on all other fields, it gives the focus to the next widget, but in the JTextArea, it inserts a tab character (horizontal space) in the text.
How can I modify this behavior?
/*
This is my understanding of how tabbing works. The focus manager
recognizes the following default KeyStrokes for tabbing:
forwards: TAB or Ctrl-TAB
backwards: Shift-TAB or Ctrl-Shift-TAB
In the case of JTextArea, TAB and Shift-TAB have been removed from
the defaults which means the KeyStroke is passed to the text area.
The TAB KeyStroke inserts a tab into the Document. Shift-TAB seems
to be ignored.
This example shows different approaches for tabbing out of a JTextArea
Also, a text area is typically added to a scroll pane. So when
tabbing forward the vertical scroll bar would get focus by default.
Each approach shows how to prevent the scrollbar from getting focus.
*/
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;
public class TextAreaTab extends JFrame
{
public TextAreaTab()
{
Container contentPane = getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
contentPane.add( nullTraversalKeys() );
contentPane.add( writeYourOwnAction() );
contentPane.add( useKeyListener() );
contentPane.add( addTraversalKeys() );
}
// Reset the text area to use the default tab keys.
// This is probably the best solution.
private JComponent nullTraversalKeys()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Null Traversal Keys\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
// scrollPane.getVerticalScrollBar().setFocusable(false);
textArea.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
textArea.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
return scrollPane;
}
// Replace the Tab Actions. A little more complicated but this is the
// only solution that will place focus on the component, not the
// vertical scroll bar, when tabbing backwards (unless of course you
// have manually prevented the scroll bar from getting focus).
private JComponent writeYourOwnAction()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Write Your Own Tab Actions\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
InputMap im = textArea.getInputMap();
KeyStroke tab = KeyStroke.getKeyStroke("TAB");
textArea.getActionMap().put(im.get(tab), new TabAction(true));
KeyStroke shiftTab = KeyStroke.getKeyStroke("shift TAB");
im.put(shiftTab, shiftTab);
textArea.getActionMap().put(im.get(shiftTab), new TabAction(false));
return scrollPane;
}
// Use a KeyListener
private JComponent useKeyListener()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Use Key Listener\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.getVerticalScrollBar().setFocusable(false);
textArea.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_TAB)
{
e.consume();
KeyboardFocusManager.
getCurrentKeyboardFocusManager().focusNextComponent();
}
if (e.getKeyCode() == KeyEvent.VK_TAB
&& e.isShiftDown())
{
e.consume();
KeyboardFocusManager.
getCurrentKeyboardFocusManager().focusPreviousComponent();
}
}
});
return scrollPane;
}
// Add Tab and Shift-Tab KeyStrokes back as focus traversal keys.
// Seems more complicated then just using null, but at least
// it shows how to add a KeyStroke as a focus traversal key.
private JComponent addTraversalKeys()
{
JTextArea textArea = new JTextArea(3, 30);
textArea.setText("Add Traversal Keys\n2\n3\n4\n5\n6\n7\n8\n9");
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.getVerticalScrollBar().setFocusable(false);
Set set = new HashSet( textArea.getFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "TAB" ) );
textArea.setFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set );
set = new HashSet( textArea.getFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "shift TAB" ) );
textArea.setFocusTraversalKeys(
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
return scrollPane;
}
class TabAction extends AbstractAction
{
private boolean forward;
public TabAction(boolean forward)
{
this.forward = forward;
}
public void actionPerformed(ActionEvent e)
{
if (forward)
tabForward();
else
tabBackward();
}
private void tabForward()
{
final KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.focusNextComponent();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (manager.getFocusOwner() instanceof JScrollBar)
manager.focusNextComponent();
}
});
}
private void tabBackward()
{
final KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.focusPreviousComponent();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if (manager.getFocusOwner() instanceof JScrollBar)
manager.focusPreviousComponent();
}
});
}
}
public static void main(String[] args)
{
TextAreaTab frame = new TextAreaTab();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
you could use the "NextWidget.grabFocus()" method within keylistener of JTextArea when key "tab" is pressed
With this latter approach the tab character will still get inserted into the JTextArea before the focus is shifted away. If you dont want that behavior you can create a subclass of JTextArea whose isManagingFocus() method always returns false, instead of true. For example:
import javax.swing.*;
public class NoTabTextArea extends JTextArea {
public boolean isManagingFocus() {
return false;
}
}
An instance of NoTabTextArea can be used exactly like a JTextArea, except that the tab key will cause the focus to shift away from it without a tab character being inserted.
You can call the following method in your main JFrame or JPanel constructor.
Use by calling as so: disableTabbingInTextAreas(this)
public static void disableTabbingInTextAreas(Component component){
if(component instanceof Container && !(component instanceof JTextArea)){
for(final Component c : ((Container) component).getComponents() ){
disableTabbingInTextAreas(c);
}
}else if(component instanceof JTextArea){
final Component c = component;
c.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyChar() == '\t'){
c.transferFocus();
e.consume();
}
}
#Override
public void keyReleased(KeyEvent e) {}
});
}
}
import javax.swing.* ;
import java.awt.event.* ;
/**
* This simple subclass of JTextArea does not allow the 'Tab'
* to be pressed. Instead of putting in 3 blank spaces, the tab
* will transfer focus
*/
/*-----------------------------------------------------------*/
/* */
/* NoTabJTextArea */
/* */
/*-----------------------------------------------------------*/
public class NoTabJTextArea extends JTextArea implements KeyListener {
public NoTabJTextArea ( String text ) {
super ( text ) ;
initialize () ;
}
public NoTabJTextArea ( ) {
super() ;
initialize() ;
}
public NoTabJTextArea ( MaskDocument document ) {
super ( document ) ;
initialize() ;
}
private void initialize () {
addKeyListener ( this ) ;
}
public void keyPressed ( KeyEvent e ) {
switch ( e.getKeyCode() ) {
case KeyEvent.VK_TAB :
e.consume() ;
transferFocus() ;
break ;
}
}
public void keyReleased ( KeyEvent e ) {
switch ( e.getKeyCode() ) {
case KeyEvent.VK_TAB :
System.out.println ( "KEY RELEASED TAB" ) ;
break ;
}
}
public void keyTyped ( KeyEvent e ) {
switch ( e.getKeyCode() ) {
case KeyEvent.VK_TAB :
System.out.println ( "KEY TYPED TAB" ) ;
break ;
}
}
} /* NoTabJTextArea */
As isManagingFocus method is deprecated since 1.4, it is also possible to use setFocusTraversalKeys. The example applies the default "on tab" behaviour to the JTextArea field.
import javax.swing.*;
import java.awt.*;
public class NoTabTextArea extends JTextArea {
public NoTabTextArea(String text, int rows, int columns) {
super(text, rows, columns);
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
}
}