JCardPane: Unterschied zwischen den Versionen
Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springenZeile 5: | Zeile 5: | ||
* The main method shows an example. | * The main method shows an example. | ||
*/ | */ | ||
− | |||
import java.awt.*; | import java.awt.*; | ||
import java.awt.event.*; | import java.awt.event.*; | ||
import java.beans.*; | import java.beans.*; | ||
import java.util.*; | import java.util.*; | ||
+ | import java.util.logging.*; | ||
import javax.swing.*; | import javax.swing.*; | ||
import javax.swing.event.*; | import javax.swing.event.*; | ||
− | import javax.swing.plaf. | + | import javax.swing.plaf.*; |
− | import javax.swing.plaf.basic. | + | import javax.swing.plaf.basic.*; |
public class JCardPane extends JComponent { | public class JCardPane extends JComponent { | ||
Zeile 58: | Zeile 58: | ||
pane.addChangeListener(new ChangeListener() { | pane.addChangeListener(new ChangeListener() { | ||
− | public void stateChanged(ChangeEvent e) { | + | @Override |
+ | public void stateChanged(final ChangeEvent e) { | ||
if (nextAction != null) { | if (nextAction != null) { | ||
nextAction.setEnabled(hasNext()); | nextAction.setEnabled(hasNext()); | ||
Zeile 68: | Zeile 69: | ||
}); | }); | ||
setLayout(new BorderLayout()); | setLayout(new BorderLayout()); | ||
− | add(pane); | + | super.add(pane); |
} | } | ||
Zeile 165: | Zeile 166: | ||
pane.setSelectedIndex(index); | pane.setSelectedIndex(index); | ||
return index; | return index; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Flips to the specified card. | ||
+ | * If the card does not exist in the cardpane, it is added to it. | ||
+ | * @return the index of the specified card | ||
+ | */ | ||
+ | public int add(final JComponent card) { | ||
+ | return show(card); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Inserts the specified card at the sepcified index and | ||
+ | * flips to the specified card. | ||
+ | */ | ||
+ | public void insertAt(JComponent card, int index){ | ||
+ | pane.insertTab(null, null, card, null, index); | ||
+ | pane.setSelectedIndex(index); | ||
} | } | ||
Zeile 191: | Zeile 210: | ||
* Adds a <code>ChangeListener</code> to this cardpane. | * Adds a <code>ChangeListener</code> to this cardpane. | ||
*/ | */ | ||
− | public void addChangeListener(ChangeListener l) { | + | public void addChangeListener(final ChangeListener l) { |
pane.addChangeListener(l); | pane.addChangeListener(l); | ||
} | } | ||
Zeile 198: | Zeile 217: | ||
* Removes a <code>ChangeListener</code> from this cardpane. | * Removes a <code>ChangeListener</code> from this cardpane. | ||
*/ | */ | ||
− | public void removeChangeListener(ChangeListener l) { | + | public void removeChangeListener(final ChangeListener l) { |
pane.removeChangeListener(l); | pane.removeChangeListener(l); | ||
} | } | ||
Zeile 205: | Zeile 224: | ||
* gets the action to be used for a "Next" button | * gets the action to be used for a "Next" button | ||
*/ | */ | ||
− | public Action getNextAction(String name) { | + | public Action getNextAction(final String name) { |
if (nextAction == null) { | if (nextAction == null) { | ||
nextAction = new CardAction(name, true); | nextAction = new CardAction(name, true); | ||
− | nextAction.putValue(Action.MNEMONIC_KEY, (int)name.charAt(0)); | + | nextAction.putValue(Action.MNEMONIC_KEY, (int) name.charAt(0)); |
nextAction.setEnabled(hasNext()); | nextAction.setEnabled(hasNext()); | ||
} | } | ||
Zeile 217: | Zeile 236: | ||
* gets the action to be used for a "Previous" button | * gets the action to be used for a "Previous" button | ||
*/ | */ | ||
− | public Action getPreviousAction(String name) { | + | public Action getPreviousAction(final String name) { |
if (previousAction == null) { | if (previousAction == null) { | ||
previousAction = new CardAction(name, false); | previousAction = new CardAction(name, false); | ||
− | previousAction.putValue(Action.MNEMONIC_KEY, (int)name.charAt(0)); | + | previousAction.putValue(Action.MNEMONIC_KEY, (int) name.charAt(0)); |
previousAction.setEnabled(hasPrevious()); | previousAction.setEnabled(hasPrevious()); | ||
} | } | ||
Zeile 227: | Zeile 246: | ||
/** | /** | ||
− | * | + | * |
* retain: if true, the component focused within a card will remain focused | * retain: if true, the component focused within a card will remain focused | ||
* each time it becomes visible, otherwise the first component of each card is focused | * each time it becomes visible, otherwise the first component of each card is focused | ||
*/ | */ | ||
− | public void retainFocus(boolean retain) { | + | public void retainFocus(final boolean retain) { |
int focusPolicy = TabFocusHandler.RESET_FOCUS; | int focusPolicy = TabFocusHandler.RESET_FOCUS; | ||
if (retain) { | if (retain) { | ||
Zeile 248: | Zeile 267: | ||
private boolean isNext; | private boolean isNext; | ||
− | + | CardAction(final String text, final boolean isNext) { | |
super(text); | super(text); | ||
this.isNext = isNext; | this.isNext = isNext; | ||
Zeile 254: | Zeile 273: | ||
} | } | ||
− | public void actionPerformed(ActionEvent e) { | + | @Override |
+ | public void actionPerformed(final ActionEvent e) { | ||
if (isNext) { | if (isNext) { | ||
next(); | next(); | ||
Zeile 271: | Zeile 291: | ||
* in which case the other policy will be in effect. | * in which case the other policy will be in effect. | ||
*/ | */ | ||
− | private class TabFocusHandler | + | private class TabFocusHandler { |
public final static int RESET_FOCUS = 0; | public final static int RESET_FOCUS = 0; | ||
public final static int RETAIN_FOCUS = 1; | public final static int RETAIN_FOCUS = 1; | ||
− | private HashMap<Component, Component> tabFocus = new HashMap<Component, Component>(); | + | private HashMap<Component, Component> tabFocus = new HashMap<Component, Component>(16); |
private HashSet<Component> exceptions; | private HashSet<Component> exceptions; | ||
private JTabbedPane tabbedPane; | private JTabbedPane tabbedPane; | ||
private int focusPolicy; | private int focusPolicy; | ||
private final KeyboardFocusManager focusManager; | private final KeyboardFocusManager focusManager; | ||
+ | private final ChangeListener changeListener; | ||
+ | private final PropertyChangeListener propertyChangeListener; | ||
/** | /** | ||
* Create with the default Retain Focus policy | * Create with the default Retain Focus policy | ||
*/ | */ | ||
− | + | TabFocusHandler(final JTabbedPane tabbedPane) { | |
this(tabbedPane, RETAIN_FOCUS); | this(tabbedPane, RETAIN_FOCUS); | ||
} | } | ||
Zeile 291: | Zeile 313: | ||
* Create using the specified focus policy | * Create using the specified focus policy | ||
*/ | */ | ||
− | + | TabFocusHandler(final JTabbedPane tabbedPane, final int focusPolicy) { | |
if (focusPolicy != RESET_FOCUS && focusPolicy != RETAIN_FOCUS) { | if (focusPolicy != RESET_FOCUS && focusPolicy != RETAIN_FOCUS) { | ||
throw new IllegalArgumentException("Invalid focus policy"); | throw new IllegalArgumentException("Invalid focus policy"); | ||
Zeile 298: | Zeile 320: | ||
this.focusPolicy = focusPolicy; | this.focusPolicy = focusPolicy; | ||
// Add listeners to manage a tab change | // Add listeners to manage a tab change | ||
− | tabbedPane.addChangeListener( | + | changeListener = new TabChangeListener(); |
+ | propertyChangeListener = new TabPropertyChangeListener(); | ||
+ | tabbedPane.addChangeListener(changeListener); | ||
focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); | focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); | ||
− | focusManager.addPropertyChangeListener("permanentFocusOwner", | + | focusManager.addPropertyChangeListener("permanentFocusOwner", propertyChangeListener); |
} | } | ||
public void uninstall() { | public void uninstall() { | ||
− | tabbedPane.removeChangeListener( | + | tabbedPane.removeChangeListener(changeListener); |
− | focusManager.removePropertyChangeListener( | + | focusManager.removePropertyChangeListener(propertyChangeListener); |
} | } | ||
Zeile 311: | Zeile 335: | ||
* Specify a tab with an exception to the focus policy rule | * Specify a tab with an exception to the focus policy rule | ||
*/ | */ | ||
− | public void addException(int index) { | + | public void addException(final int index) { |
if (exceptions == null) { | if (exceptions == null) { | ||
− | exceptions = new HashSet<Component>(); | + | exceptions = new HashSet<Component>(16); |
} | } | ||
Component key = tabbedPane.getComponentAt(index); | Component key = tabbedPane.getComponentAt(index); | ||
Zeile 319: | Zeile 343: | ||
} | } | ||
− | + | private class TabPropertyChangeListener implements PropertyChangeListener { | |
− | + | ||
− | + | TabPropertyChangeListener() { | |
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | ||
− | + | /** | |
− | + | * Track focus changes and update the current focus component | |
− | key. | + | * for the current tab |
− | + | */ | |
− | + | @Override | |
− | + | public void propertyChange(final PropertyChangeEvent e) { | |
− | value. | + | // No need to track focus change |
+ | if (exceptions == null && focusPolicy == RESET_FOCUS) { | ||
+ | return; | ||
+ | } | ||
+ | Component key = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); | ||
+ | if (exceptions != null) { | ||
+ | if (focusPolicy == RESET_FOCUS && !exceptions.contains(key)) { | ||
+ | return; | ||
+ | } | ||
+ | if (focusPolicy == RETAIN_FOCUS && exceptions.contains(key)) { | ||
+ | return; | ||
+ | } | ||
+ | } | ||
+ | Component value = (Component) e.getNewValue(); | ||
+ | if (value != null && SwingUtilities.isDescendingFrom(value, key)) { | ||
+ | tabFocus.put(key, value); | ||
+ | } | ||
} | } | ||
} | } | ||
− | + | private class TabChangeListener implements ChangeListener { | |
− | + | ||
− | + | TabChangeListener() { | |
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | / | + | |
− | Component key = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); | + | /** |
− | + | * Tab has changed. Focus on saved component for the given tab. | |
− | if ( | + | * When there is no saved component, focus on the first component. |
+ | */ | ||
+ | @Override | ||
+ | public void stateChanged(final ChangeEvent e) { | ||
+ | Component key = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); | ||
+ | if (key == null) { | ||
return; | return; | ||
} | } | ||
− | if ( | + | Component value = tabFocus.get(key); |
− | + | // First time selecting this tab or focus policy is RESET_FOCUS | |
+ | if (value == null) { | ||
+ | key.transferFocus(); | ||
+ | tabFocus.put(key, value); | ||
+ | } else // Use the saved component for focusing | ||
+ | { | ||
+ | value.requestFocusInWindow(); | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
} | } | ||
Zeile 367: | Zeile 403: | ||
//for testing only: | //for testing only: | ||
− | public static void main(final String | + | public static void main(final String... args) { |
try { | try { | ||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | ||
− | } catch ( | + | } catch (ClassNotFoundException ex) { |
− | ex. | + | Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); |
+ | } catch (InstantiationException ex) { | ||
+ | Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); | ||
+ | } catch (IllegalAccessException ex) { | ||
+ | Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); | ||
+ | } catch (UnsupportedLookAndFeelException ex) { | ||
+ | Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); | ||
} | } | ||
Runnable gui = new Runnable() { | Runnable gui = new Runnable() { | ||
Zeile 385: | Zeile 427: | ||
class Card extends JPanel { | class Card extends JPanel { | ||
− | + | Card(final String name) { | |
JTextField tf = new JTextField(20); | JTextField tf = new JTextField(20); | ||
tf.setText(name); | tf.setText(name); |
Version vom 16. März 2011, 11:25 Uhr
<code=java> /*
* JCardPane.java * wraps a JTabbedPane, hiding the tabs. * The main method shows an example. */
import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.*; import java.util.logging.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*;
public class JCardPane extends JComponent {
private JTabbedPane pane; private CardAction nextAction; private CardAction previousAction; private TabFocusHandler tabFocusHandler; private TabbedPaneUI uiNoTabs = new BasicTabbedPaneUI() {
@Override protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, int maxTabHeight) { return 0; }
@Override protected Insets getContentBorderInsets(int tabPlacement) { return new Insets(0, 0, 0, 0); }
@Override protected MouseListener createMouseListener() { return null; }
@Override protected void installKeyboardActions() { }
@Override protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { return 0; } };
/** * Creates an empty cardpane */ public JCardPane() { pane = new JTabbedPane(); tabFocusHandler = new TabFocusHandler(pane); hideTabs(); pane.addChangeListener(new ChangeListener() {
@Override public void stateChanged(final ChangeEvent e) { if (nextAction != null) { nextAction.setEnabled(hasNext()); } if (previousAction != null) { previousAction.setEnabled(hasPrevious()); } } }); setLayout(new BorderLayout()); super.add(pane); }
/** * Flips to the first card of the cardpane. * @return 0 if this cardpane has a card * or -1 if this cardpane has no card */ public int first() { return show(0); }
/** * Flips to the last card of the cardpane. * @return 0 if this cardpane has a card * or -1 if this cardpane has no card */ public int last() { return show(-1); }
/** * Flips to the next card of the cardpane. * If the currently visible card is the last one, * this method flips to the first card of the cardpane. * @return the index of the card * or -1 if this cardpane has no card */ public int next() { return show(pane.getSelectedIndex() + 1); }
/** * Flips to the previous card of the cardpane. * If the currently visible card is the first one, * this method flips to the last card of the cardpane. * @return the index of the card * or -1 if this cardpane has no card */ public int previous() { return show(pane.getSelectedIndex() - 1); }
/** * Flips to the card at the specified index. * If the index is positive but does not exist, * this method flips to the first card of the cardpane. * If the index is negative, * this method flips to the last card of the cardpane. * @return the index of the card * or -1 if this cardpane has no card */ public int show(final int index) { if (pane.getTabCount() == 0) { return -1; } if (index >= pane.getTabCount()) { pane.setSelectedIndex(0); return 0;
} if (index < 0) { pane.setSelectedIndex(pane.getTabCount() - 1); return pane.getTabCount() - 1;
} pane.setSelectedIndex(index); return index; }
/** * Flips to the card with the specified name. * If the name does not exist, nothing happens. * @return the index of the card * or -1 if the name does not exist */ public int show(final String name) { int index = pane.indexOfTab(name); if (index >= 0) { pane.setSelectedIndex(index); } return index; }
/** * Flips to the specified card. * If the card does not exist in the cardpane, it is added to it. * @return the index of the specified card */ public int show(final JComponent card) { int index = pane.indexOfComponent(card); if (index < 0) { index = pane.getTabCount(); pane.addTab(card.getName(), card); } pane.setSelectedIndex(index); return index; }
/** * Flips to the specified card. * If the card does not exist in the cardpane, it is added to it. * @return the index of the specified card */ public int add(final JComponent card) { return show(card); }
/** * Inserts the specified card at the sepcified index and * flips to the specified card. */ public void insertAt(JComponent card, int index){ pane.insertTab(null, null, card, null, index); pane.setSelectedIndex(index); }
/** * @return true if there is a card after the visible one */ public boolean hasNext() { return pane.getSelectedIndex() < pane.getComponentCount() - 1; }
/** * @return true if there is a card before the visible one */ public boolean hasPrevious() { return pane.getSelectedIndex() > 0; }
/** * @return the visible card */ public Component getCurrent() { return pane.getSelectedComponent(); }
/**
* Adds a ChangeListener
to this cardpane.
*/
public void addChangeListener(final ChangeListener l) {
pane.addChangeListener(l);
}
/**
* Removes a ChangeListener
from this cardpane.
*/
public void removeChangeListener(final ChangeListener l) {
pane.removeChangeListener(l);
}
/** * gets the action to be used for a "Next" button */ public Action getNextAction(final String name) { if (nextAction == null) { nextAction = new CardAction(name, true); nextAction.putValue(Action.MNEMONIC_KEY, (int) name.charAt(0)); nextAction.setEnabled(hasNext()); } return nextAction; }
/** * gets the action to be used for a "Previous" button */ public Action getPreviousAction(final String name) { if (previousAction == null) { previousAction = new CardAction(name, false); previousAction.putValue(Action.MNEMONIC_KEY, (int) name.charAt(0)); previousAction.setEnabled(hasPrevious()); } return previousAction; }
/** * * retain: if true, the component focused within a card will remain focused * each time it becomes visible, otherwise the first component of each card is focused */ public void retainFocus(final boolean retain) { int focusPolicy = TabFocusHandler.RESET_FOCUS; if (retain) { focusPolicy = TabFocusHandler.RETAIN_FOCUS; } tabFocusHandler.uninstall(); tabFocusHandler = new TabFocusHandler(pane, focusPolicy); }
private void hideTabs() { pane.setUI(uiNoTabs); }
private class CardAction extends AbstractAction {
private boolean isNext;
CardAction(final String text, final boolean isNext) { super(text); this.isNext = isNext; putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); }
@Override public void actionPerformed(final ActionEvent e) { if (isNext) { next(); } else { previous(); } } }
/** * Manage the focus when a new tab is selected. You can select a focus policy: * a) Reset Focus - focus is reset to the first focusable component on the tab * b) Retain Focus - focus returns to the last component with focus on the tab * * In addition you add tabs that you want to exclude from the focus policy, * in which case the other policy will be in effect. */ private class TabFocusHandler {
public final static int RESET_FOCUS = 0; public final static int RETAIN_FOCUS = 1; private HashMap<Component, Component> tabFocus = new HashMap<Component, Component>(16); private HashSet<Component> exceptions; private JTabbedPane tabbedPane; private int focusPolicy; private final KeyboardFocusManager focusManager; private final ChangeListener changeListener; private final PropertyChangeListener propertyChangeListener;
/** * Create with the default Retain Focus policy */ TabFocusHandler(final JTabbedPane tabbedPane) { this(tabbedPane, RETAIN_FOCUS); }
/** * Create using the specified focus policy */ TabFocusHandler(final JTabbedPane tabbedPane, final int focusPolicy) { if (focusPolicy != RESET_FOCUS && focusPolicy != RETAIN_FOCUS) { throw new IllegalArgumentException("Invalid focus policy"); } this.tabbedPane = tabbedPane; this.focusPolicy = focusPolicy; // Add listeners to manage a tab change changeListener = new TabChangeListener(); propertyChangeListener = new TabPropertyChangeListener(); tabbedPane.addChangeListener(changeListener); focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); focusManager.addPropertyChangeListener("permanentFocusOwner", propertyChangeListener); }
public void uninstall() { tabbedPane.removeChangeListener(changeListener); focusManager.removePropertyChangeListener(propertyChangeListener); }
/** * Specify a tab with an exception to the focus policy rule */ public void addException(final int index) { if (exceptions == null) { exceptions = new HashSet<Component>(16); } Component key = tabbedPane.getComponentAt(index); exceptions.add(key); }
private class TabPropertyChangeListener implements PropertyChangeListener {
TabPropertyChangeListener() { }
/** * Track focus changes and update the current focus component * for the current tab */ @Override public void propertyChange(final PropertyChangeEvent e) { // No need to track focus change if (exceptions == null && focusPolicy == RESET_FOCUS) { return; } Component key = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); if (exceptions != null) { if (focusPolicy == RESET_FOCUS && !exceptions.contains(key)) { return; } if (focusPolicy == RETAIN_FOCUS && exceptions.contains(key)) { return; } } Component value = (Component) e.getNewValue(); if (value != null && SwingUtilities.isDescendingFrom(value, key)) { tabFocus.put(key, value); } } }
private class TabChangeListener implements ChangeListener {
TabChangeListener() { }
/** * Tab has changed. Focus on saved component for the given tab. * When there is no saved component, focus on the first component. */ @Override public void stateChanged(final ChangeEvent e) { Component key = tabbedPane.getComponentAt(tabbedPane.getSelectedIndex()); if (key == null) { return; } Component value = tabFocus.get(key); // First time selecting this tab or focus policy is RESET_FOCUS if (value == null) { key.transferFocus(); tabFocus.put(key, value); } else // Use the saved component for focusing { value.requestFocusInWindow(); } } } }
//for testing only: public static void main(final String... args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException ex) { Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); } catch (InstantiationException ex) { Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); } catch (UnsupportedLookAndFeelException ex) { Logger.getLogger(JCardPane.class.getName()).log(Level.SEVERE, null, ex); } Runnable gui = new Runnable() {
@Override public void run() { final JFrame f = new JFrame("JCardPane Demo"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(400, 150); f.setLocationRelativeTo(null); final JCardPane cardPane = new JCardPane(); f.add(cardPane, BorderLayout.CENTER); class Card extends JPanel {
Card(final String name) { JTextField tf = new JTextField(20); tf.setText(name); add(tf); tf = new JTextField(20); tf.setText(name); add(tf); setName(name); } } for (int i = 0; i < 5; i++) { cardPane.show(new Card(String.valueOf(i + 1))); } cardPane.first(); JPanel control = new JPanel(); control.add(new JButton(cardPane.getPreviousAction("Previous"))); control.add(new JButton(cardPane.getNextAction("Next"))); f.add(control, BorderLayout.SOUTH); f.setVisible(true); } }; //GUI must start on EventDispatchThread: SwingUtilities.invokeLater(gui); }
} </code=java>