I am trying to implement a listener to detect the closing of a window. My main class is extending other classes so I am unable to extend JFrame which is not allowing me to use addWindowListener.
I have tried the code below but it is not working.
public class PowerPanel extends AnotherPanel implements ActionListener, PropertyChangeListener {
// logic …
this.addWindowListener(new WindowAdapter() {
public void windowClosing (WindowEvent e ) {
// do things
}
});
}
The error I am getting is indicating that addWindowListener is "undefined for the type PowerPanel."
You can't add window listener to your panel - you need to add it into the java.awt.Window instance which in your case is a JFrame.
If it is hard for you to pass your JFrame instance into the panel - you can access it in a different way:
public class SamplePanel extends JPanel
{
/**
* Simple panel example that has no idea about it's parent window.
*/
public SamplePanel ()
{
super ();
// Your custom window listener
final WindowAdapter windowAdapter = new WindowAdapter ()
{
#Override
public void windowClosing ( final WindowEvent e )
{
System.out.println ( "Window is closing" );
}
};
// Ancestor availability listener
// It will make sure that whenever component appears on some visible window
// and is displayable container - we will add our window listener to it
addAncestorListener ( new AncestorAdapter ()
{
/**
* Saved window to remove listener from later on.
*/
private Window window = null;
#Override
public void ancestorAdded ( final AncestorEvent event )
{
// Component appeared on some window, we can add our listener now
addListener ();
}
#Override
public void ancestorMoved ( final AncestorEvent event )
{
// Re-adding listener to potentially new parent window
removeListener ();
addListener ();
}
#Override
public void ancestorRemoved ( final AncestorEvent event )
{
// Component was hidden or removed, we need to remove our listener
removeListener ();
}
/**
* Adds window listener.
*/
protected void addListener ()
{
window = SwingUtilities.getWindowAncestor ( SamplePanel.this );
if ( window != null )
{
window.addWindowListener ( windowAdapter );
}
}
/**
* Removes window listener.
*/
protected void removeListener ()
{
if ( window != null )
{
window.removeWindowListener ( windowAdapter );
window = null;
}
}
} );
}
/**
* Sample main method for runing the example.
*
* #param args arguments
*/
public static void main ( final String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
#Override
public void run ()
{
final JFrame frame = new JFrame ();
final SamplePanel panel = new SamplePanel ();
panel.add ( new JLabel ( "Sample panel content" ) );
frame.add ( panel );
frame.pack ();
frame.setDefaultCloseOperation ( JFrame.DISPOSE_ON_CLOSE );
frame.setLocationRelativeTo ( null );
frame.setVisible ( true );
}
} );
}
}
With this code your panel will automatically register window listener on it's parent window whenever it is displayed. It will also automatically remove the listener once panel is hidden or removed from the window, so potentially this is the best solution you can have.
Be careful though, if you will use that panel multiple times on the same window - all of the instances will add their own listener and will all perform on-close action separately. If you want to perform your on-close operation just once per window/frame/dialog instance - you need to add the listener on the window itself, preferably where it is created not to make it obscure.
You might also notice that in my example there is actually a method that retrieves panel's parent window directly:
window = SwingUtilities.getWindowAncestor ( SamplePanel.this );
Although you can't use it in your panel directly, because at the moment when panel is created it is not yet added into any container, let alone visible window. That is why the solution with ancestor listener that i've shown is required.
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 has a MouseAdapter that I use to drag a window around simply by clicking its background, like so:
public class Dragger extends MouseAdapter{
private Point offset;
private Window window;
public Dragger(Window w){
window = w;
}
#Override
public void mousePressed(MouseEvent e){
offset = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e){
Point m = e.getLocationOnScreen();
window.setLocation(m.x - offset.x, m.y - offset.y);
}
}
Simple as, right?
And I add it to the JFrame I'm using it on (I'm using it on a JDialogUE as well, hence the 'Window':
// Drag Listeners
Dragger dr = new Dragger(this);
addMouseListener(dr);
addMouseMotionListener(dr);
The drag (currently) only works when I construct a new Dragger, then add it as both a MouseListener and MouseMotionListener.
Is there a nicer, prettier, more elegant, more traditionally sound, more professionally robust, so it goes, way of doing it in just one method?
In such cases I would suggest writing helper static methods within the Dragger class:
public class Dragger extends MouseAdapter
{
private Point offset;
private Window window;
public Dragger ( final Window w )
{
window = w;
}
#Override
public void mousePressed ( final MouseEvent e )
{
offset = e.getPoint ();
}
#Override
public void mouseDragged ( final MouseEvent e )
{
final Point m = e.getLocationOnScreen ();
window.setLocation ( m.x - offset.x, m.y - offset.y );
}
public static void install ( final Window window )
{
final Dragger dr = new Dragger ( window );
window.addMouseListener ( dr );
window.addMouseMotionListener ( dr );
}
public static void uninstall ( final Window window )
{
for ( final MouseListener mouseListener : window.getMouseListeners () )
{
if ( mouseListener instanceof Dragger )
{
window.removeMouseListener ( mouseListener );
}
}
for ( final MouseMotionListener mouseMotionListener : window.getMouseMotionListeners () )
{
if ( mouseMotionListener instanceof Dragger )
{
window.removeMouseMotionListener ( mouseMotionListener );
}
}
}
}
And then simply call Dragger.install(window) and Dragger.uninstall(window).
Not sure whether it is a good approach or not, but it takes less space and might also ensure that you don't add Dragger twice if you add some more checks into install method - of course if you don't want to have Dragger installed twice on the same window.
Also in that case you don't need to look in your code for the usage of this class since you are sure how it will be installed and uninstalled and can change that behavior in one place instead of modifying lots of add*Listener calls.
I have a public class AppHelper for displaying some help content using a jframe. There is an exit button on the same JFrame which on click disposes the jframe.
The ActionListener is implemented as a static nested class of the class mentioned above.
Also all the components of the help window are defined in the outer class and all of them are private and static. Also the method that shows the help window is static.
Here is some code that I have implemented:
public class AppHelper {
// helper frame
private static JFrame appHelperFrame;
// helper panel
private static JPanel appHelperPanel;
// helper pane
private static JEditorPane appHelperPane;
// exit helper button
private static JButton exitAppHelperButton;
// constraints
private static GridBagConstraints appHelperPaneCons, exitAppHelperButtonCons;
/**
set layout
*/
private static void setLayoutConstraints () {
// defines layout
}
/**
* initialize the helper elements
* #param void
* #return void
*/
public static void initializeElements () {
// initialize constraints
setLayoutConstraints();
// handler
AppHelper.AppHelperHandler appHelpHandler = new AppHelper.AppHelperHandler();
appHelperFrame = new JFrame("App Help");
appHelperPanel = new JPanel();
appHelperPanel.setLayout(new GridBagLayout());
appHelperPane = new JEditorPane();
exitAppHelperButton = new JButton("Exit");
exitAppHelperButton.addActionListener(appHelpHandler);
java.net.URL helpURL = null;
try {
helpURL = new File("AppHelp.html").toURI().toURL();
} catch (MalformedURLException ex) {
Logger.getLogger(AppHelper.class.getName()).log(Level.SEVERE, null, ex);
}
try {
appHelperPane.setPage(helpURL);
} catch (IOException ex) {
Logger.getLogger(AppHelper.class.getName()).log(Level.SEVERE, null, ex);
}
appHelperPane.setEditable(false);
appHelperFrame.add(appHelperPanel);
appHelperPanel.add(appHelperPane, appHelperPaneCons);
appHelperPanel.add(exitAppHelperButton, exitAppHelperButtonCons);
appHelperFrame.setSize(350, 400);
appHelperFrame.setResizable(false);
appHelperFrame.setVisible(true);
}
/**
* TODO
*/
public static void showAboutApp() {
//throw new UnsupportedOperationException("Not yet implemented");
}
/**
*
* Acts as the handler for the help window components
* Implement actionListener interface.
*/
private static class AppHelperHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if(source == exitAppHelperButton) {
appHelperFrame.dispose();
}
}
}
}
The reason of disposing the JFrame instead of setting it invisible is that I dont want this JFrame to consume memory when this JFrame is not in use.
Now the problem is first time I click on the help button (on some other window) the JFrame is shown. Now when I click the exit button on this help window the JFrame is disposed by the handler. Next time I again click on the help button, the help window is not shown. I wanted to know if there is any error in my code or I need to do some thing else.
The javadoc of Window.dispose() states that
The Window and its subcomponents can be made displayable again by rebuilding the native resources with a subsequent call to pack or show.
And that works too, I've tried it. Just call appHelperFrame.setVisible(true) and that's all. If the window is not activated, try calling appHelperFrame.setState(Frame.NORMAL) which will acitvate it.
You only have to call your initializeElements method once though. Your showAboutApp() method should look something like this:
public static void showAboutApp() {
if (appHelperFrame == null)
initializeElements(); // This also makes the frame visible
else {
appHelperFrame.setVisible(true);
appHelperFrame.setState(Frame.NORMAL);
}
}
Final note:
If you always call this showAboutApp() from the EDT (Event Dispatching Thread) then you're good. If you call this from multiple threads, you might want to execute it in the EDT with like SwingUtilities.invokeAndwait() or SwingUtilities.invokeLater() which also ensures synchronization between multiple threads.
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'm trying to write an app that goes something like this:
- Display a dialog
- When user clicks OK, close dialog, go to main app
Here are the relevant code snippets:
public class Owari extends JPanel implements ActionListener, MouseListener, Runnable {
// FIELDS
JFrame frame;
JTextField IP;
String IPAddress;
static final int SERVER_MODE = 0;
static final int CLIENT_MODE = 1;
int mode;
OwariBoard board;
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Owari() );
}
Owari() {
setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
board = new OwariBoard();
}
void main() {
this.addMouseListener( this );
frame.dispose();
frame = new JFrame( "Owari" );
frame.setContentPane( this );
frame.pack();
frame.setVisible(true);
if ( mode == SERVER_MODE ) {
server();
}
if ( mode == CLIENT_MODE ) {
client();
}
}
public void run() {
frame = new JFrame( "Owari" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
JPanel init = new JPanel( new GridBagLayout() );
frame.setContentPane( init );
add some components to the init panel including a button with
this as its actionListener and OK as its command.
frame.pack();
frame.setVisible( true );
}
public void actionPerformed( ActionEvent e ) {
if ( e.getActionCommand().equals( "Client" ) ) {
mode = CLIENT_MODE;
IP.setVisible( true );
}
else if ( e.getActionCommand().equals( "Server" ) ) {
mode = SERVER_MODE;
IP.setVisible( false );
}
else {
IPAddress = IP.getText();
main();
}
}
public void paintComponent( Graphics g ) {
super.paintComponent( g );
System.out.println( "painting" );
do some paintin
}
void server() {
frame.setTitle( "Owari Server" );
try {
server = new ServerSocket( 666 );
socket = server.accept();
initIO();
} catch ( IOException e ) {}
yourTurn = true;
System.out.println( "Got to end of server()" ); // At this point, the window
DOES get painted
What happens is the following:
The initial dialog displays:
I click the OK button.
The main window gets resized to the preferred size of the main app but it doesn't get painted, it's just transparent (shown here with this page as the background, heh):
http://imgur.com/6Ssij.jpg
I can tell the paintComponent method hasn't been called because "painting" isn't printed to the console.
However, "got to this point in the program" DOES get printed, so the program isn't hanging, it's just not calling paintComponent.
Then when I launch a client and connect, the app finally gets painted, and "painting" and "got a client" get printed to the console.
Also later on in the app, calls to repaint() are delayed (ie paintComponent is actually called later in the program than when the call to repaint() is made).
I also tried replacing the initial dialog using sthing along the lines of
public void main
frame.getRootPane.removeAll()
frame.setContentPane(this)
frame.getRootPane().revalidate()
frame.pack()
Exact same result.
tl;dr paintcomponent isn't being called when i want it to, what do?
Bumping for some more info: the call to repaint() is done before the call to sever.accept() So why does it not repaint() before hanging at the server.accept() call?
openasocketandwaitforaclient
Your code is executing in the Event Dispatch Thread so the blocking socket is preventing the GUI from repainting itself.
YOu need to use a separate Thread for the socket. Read the section from the Swing tutorial on Concurrency for an explanation and a solution.
your code seems to work so, maybe you should try to invoke the repaint() methode of you frame after resizing this frame.
Anhuin