JCardPane: Unterschied zwischen den Versionen
Aus Byte-Welt Wiki
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| Zeile 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>
