Java Swing - Show glasspane and consume events without losing previous focus owner - java

We are trying to show the user a milky JGlassPane to indicate that events are currently not accepted, due to a progress-bar or something else currently being shown. While this would usually automatically work, since we are showing a modal dialog, we also want the JGlassPane to be usable without a JDialog, meaning just a JGlassPane and a waiting cursor.
So far, we did this by using a JGlassPane that ignores events and paints a translucent color. Initially we call requestFocus on the JGlassPane. The problem with this is, that we lose the previously focused components when the glasspane goes away. The solution for this was to simply remember the previously focused component. However, in cases where the Action, that triggered the JGlassPane, was invoked via a menu, the focused component was the windows JRootPane. Usually swing correctly restores the focus after closing a menu, however, in this case, we are breaking this functionallity. Is there a way to achieve what we want without breaking the focus behaviour?
In this demo you can see, that the focus is correctly returned when hitting ESC after using one of the two buttons, but not with the context menu on the table.
public class FocusDemo
{
//Temporary static veriable for demo purposes.
private static final AtomicReference<Component> previouslyFocused = new AtomicReference<>();
private static class ConsumingGlassPane extends JPanel
{
public ConsumingGlassPane()
{
setOpaque( false );
setFocusable( true );
addMouseListener( new MouseListener()
{
#Override
public void mouseClicked( #NonNull final MouseEvent e )
{
e.consume();
}
#Override
public void mousePressed( #NonNull final MouseEvent e )
{
e.consume();
}
#Override
public void mouseReleased( #NonNull final MouseEvent e )
{
e.consume();
}
#Override
public void mouseEntered( #NonNull final MouseEvent e )
{
e.consume();
}
#Override
public void mouseExited( #NonNull final MouseEvent e )
{
e.consume();
}
} );
addKeyListener( new KeyListener()
{
#Override
public void keyTyped( final KeyEvent e )
{
e.consume();
}
#Override
public void keyReleased( final KeyEvent e )
{
e.consume();
}
#Override
public void keyPressed( final KeyEvent e )
{
if ( e.getKeyCode() == KeyEvent.VK_ESCAPE )
{
setVisible( false );
final Component component = previouslyFocused.get();
if ( component != null )
{
component.requestFocusInWindow();
}
}
e.consume();
}
} );
// This component keeps the focus until is made hidden
setInputVerifier( new InputVerifier()
{
#Override
public boolean verify( final JComponent input )
{
return !isVisible();
}
} );
}
#Override
protected void paintComponent( final Graphics g )
{
final Graphics2D g2 = (Graphics2D) g.create();
g2.setColor( new Color( 240, 230, 230, 128 ) );
g2.fillRect( 0, 0, getWidth(), getHeight() );
g2.dispose();
}
}
public static void main( final String[] args )
{
final JFrame frame = new JFrame();
frame.setGlassPane( new ConsumingGlassPane() );
final ActionListener showglasspane = __ ->
{
previouslyFocused.set( frame.getFocusOwner() );
frame.getRootPane().getGlassPane().setVisible( true );
frame.getRootPane().getGlassPane().requestFocus();
};
final JButton button1 = new JButton( "Show GlassPane" );
final JButton button2 = new JButton( "Show GlassPane" );
button1.addActionListener( showglasspane );
button2.addActionListener( showglasspane );
final Object[][] objects = { { 1, 2, 3 }, { 1, 2, 3 } };
final String[] col = { "Lel", "Lol", "Lul" };
final JTable table = new JTable( objects, col );
final JMenuItem menuItem = new JMenuItem( "Show GlassPane" );
menuItem.addActionListener( showglasspane );
final JPopupMenu popup = new JPopupMenu();
popup.add( menuItem );
table.setComponentPopupMenu( popup );
frame.setLayout( new GridBagLayout() );
frame.add( button1 );
frame.add( button2 );
frame.add( table );
frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}

Related

How can I find out which keys are pressed without a listener? [duplicate]

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));
}
}

JTabbedPane. Select tab on left mouse button click only

I want to set the most common JTabbedPane mouse event behavior, but I cannot find appropriate options to set:
Left mouse button click - Select tab.
Right mouse button click - Open current tab' dropdown menu.
Wheel mouse button click - Close the tab.
Question: Is there any way to implement them?
PS: Any example from here could be an SSCCE.
Tab selection is performed with left mouse button by default, so you don't need to add that feature. Everything else you can find in this small example:
public static void main ( String[] args )
{
final JFrame frame = new JFrame ();
final JTabbedPane tabbedPane = new JTabbedPane ();
tabbedPane.addTab ( "tab1", new JLabel ( "" ) );
tabbedPane.addTab ( "tab2", new JLabel ( "" ) );
tabbedPane.addTab ( "tab3", new JLabel ( "" ) );
tabbedPane.addTab ( "tab4", new JLabel ( "" ) );
frame.add ( tabbedPane );
tabbedPane.setUI ( new MetalTabbedPaneUI ()
{
protected MouseListener createMouseListener ()
{
return new CustomAdapter ( tabbedPane );
}
} );
frame.pack ();
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
frame.setVisible ( true );
}
private static class CustomAdapter extends MouseAdapter
{
private JTabbedPane tabbedPane;
public CustomAdapter ( JTabbedPane tabbedPane )
{
super ();
this.tabbedPane = tabbedPane;
}
public void mousePressed ( MouseEvent e )
{
final int index = tabbedPane.getUI ().tabForCoordinate ( tabbedPane, e.getX (), e.getY () );
if ( index != -1 )
{
if ( SwingUtilities.isLeftMouseButton ( e ) )
{
if ( tabbedPane.getSelectedIndex () != index )
{
tabbedPane.setSelectedIndex ( index );
}
else if ( tabbedPane.isRequestFocusEnabled () )
{
tabbedPane.requestFocusInWindow ();
}
}
else if ( SwingUtilities.isMiddleMouseButton ( e ) )
{
tabbedPane.removeTabAt ( index );
}
else if ( SwingUtilities.isRightMouseButton ( e ) )
{
final JPopupMenu popupMenu = new JPopupMenu ();
final JMenuItem addNew = new JMenuItem ( "Add new" );
addNew.addActionListener ( new ActionListener ()
{
public void actionPerformed ( ActionEvent e )
{
tabbedPane.addTab ( "tab", new JLabel ( "" ) );
}
} );
popupMenu.add ( addNew );
final JMenuItem close = new JMenuItem ( "Close" );
close.addActionListener ( new ActionListener ()
{
public void actionPerformed ( ActionEvent e )
{
tabbedPane.removeTabAt ( index );
}
} );
popupMenu.add ( close );
final JMenuItem closeAll = new JMenuItem ( "Close all" );
closeAll.addActionListener ( new ActionListener ()
{
public void actionPerformed ( ActionEvent e )
{
tabbedPane.removeAll ();
}
} );
popupMenu.add ( closeAll );
final Rectangle tabBounds = tabbedPane.getBoundsAt ( index );
popupMenu.show ( tabbedPane, tabBounds.x, tabBounds.y + tabBounds.height );
}
}
}
}
Ofcourse you'd better save the displayed menu somewhere so it won't be recreated every time user opens it. You can also move the mouse listener to a separate class to use it every time you need menu and other features.
But my goal was to show you how those things can be done and not making a perfect example, so i guess it is more than enough to start working with tabbed pane :)

Trying to update my JFrame, why won't repaint work?

I will run the program, but when I activate the event, the JFrame will not update (it only removes the JLabel ) unless I manually drag the window to resize it, even with the repaint() being called after the event takes place. What's wrong?
public Driver() {
setLayout( new FlowLayout() );
pass = new JPasswordField( 4 );
add( pass );
image = new ImageIcon( "closedD.png" );
label = new JLabel( "Enter the password to enter the journal of dreams" , image , JLabel.LEFT );
add( label );
button = new JButton( "Enter" );
add( button );
event e = new event();
button.addActionListener( e );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setVisible( true );
setSize( 1600/2 , 900/2 );
setTitle( "Diary" );
}
//main method
//
//
public static void main( String[] args ) {
win = new Driver();
}
public class event implements ActionListener {
private boolean clickAgain = false;
public void actionPerformed( ActionEvent e ) {
if ( passEquals( password ) && clickAgain == false ) {
image2 = new ImageIcon( "openD.png" );
remove( label );
label = new JLabel( "Good Job! Here is the journal of dreams." , image2 , JLabel.LEFT );
add( label );
clickAgain = true;
}
repaint();
}
}
Any time you add or remove a component, you must tell its container to re-layout the current components it holds. You do this by calling revalidate() on it. You would then call repaint() after the revalidate call to have the container repaint itself.
public void actionPerformed( ActionEvent e ) {
if ( passEquals( password ) && clickAgain == false ) {
image2 = new ImageIcon( "openD.png" );
remove( label );
label = new JLabel( "Good Job! Here is the journal of dreams.",
image2 , JLabel.LEFT );
add( label );
clickAgain = true;
}
revalidate(); // **** added ****
repaint();
}
Note: your question is worded in such a way as if you assume that we know what you're trying to do. Please give us more information next time. The better and more informative the question, the better and more informative the answer.
Edit 2:
I wonder if you could simplify your code a bit. Instead of removing and adding a JLabel, better to just simply set the current JLabel's text and Icon:
public void actionPerformed( ActionEvent e ) {
if ( passEquals( password ) && clickAgain == false ) {
image2 = new ImageIcon( "openD.png" );
// remove( label ); // removed
label.setText( "Good Job! Here is the journal of dreams.");
label.setIcon(image2);
}
}

How can I modify the behavior of the tab key in a JTextArea?

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));
}
}

How to change the jtooltip timers for 1 component

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..

Categories

Resources