📄 tabpanel.java
字号:
package com.magelang.tabsplitter;
import java.awt.Panel;
import java.awt.PopupMenu;
import java.awt.MenuItem;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Font;
import java.awt.Component;
import java.awt.Polygon;
import java.util.Vector;
import java.util.Hashtable;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.Image;
import java.awt.Rectangle;
/**
* TabPanel -- allows a user to select from several interface components
* by clicking a tab at the top of the panel.
*
* Note that this class is only dependent on the JDK; no other class
* libraries or files are necessary
*
* <p>Each contained component is represented by a tab at the top of the
* TabPanel, much like file folders in a file cabinet. When a
* tab is clicked, it becomes the "selected" tab and its associated
* component will be displayed.
* <p>There are two types of navigational aids provided with the
* TabPanel. If there are more tabs than can be displayed in the
* current window, two triangle buttons will appear. These buttons
* will scroll the set of tabs left and right.
* <p>There are also two buttons marked "+" and "-". These
* buttons move the user through each tab in succession.
* <p>To properly set up a tab panel, you need to do two things:
* <ul>
* <li>add components to the TabPanel, using an "add" method.
* <br>The order in which panels are added is the
* order in which their tabs will appear.
* <li>set a tabText string array to represent the text that
* is displayed on each tab.
* </ul>
*
* <p><b>Note:</b> It is extremely important that the user of this
* tab panel not try to directly use the layoutmanger (via getLayout()
* and setLayout() ). These two methods could not be overridden
* to prevent modification, as many GUI builders expect to use it.
* If you want to switch between tabs, use the "next()" and "previous()"
* methods provided by TabSplitter, <i>not</i> those of CardLayout.
*
* <p>Use this code at your own risk! MageLang Institute is not
* responsible for any damage caused directly or indirectly through
* use of this code.
* <p><p>
* <b>SOFTWARE RIGHTS</b>
* <p>
* TabSplitter, version 2.0, Scott Stanchfield, MageLang Institute
* <p>
* We reserve no legal rights to this code--it is fully in the
* public domain. An individual or company may do whatever
* they wish with source code distributed with it, including
* including the incorporation of it into commerical software.
*
* <p>However, this code <i>cannot</i> be sold as a standalone product.
* <p>
* We encourage users to develop software with this code. However,
* we do ask that credit is given to us for developing it
* By "credit", we mean that if you use these components or
* incorporate any source code into one of your programs
* (commercial product, research project, or otherwise) that
* you acknowledge this fact somewhere in the documentation,
* research report, etc... If you like these components and have
* developed a nice tool with the output, please mention that
* you developed it using these components. In addition, we ask that
* the headers remain intact in our source code. As long as these
* guidelines are kept, we expect to continue enhancing this
* system and expect to make other tools available as they are
* completed.
* <p>
* The MageLang Support Classes Gang:
* @version TabSplitter 2.0, MageLang Insitute, Jan 18, 1998
* @author <a href="http:www.scruz.net/~thetick">Scott Stanchfield</a>, <a href=http://www.MageLang.com>MageLang Institute</a>
* @see SplitterLayout
*/
public class TabPanel extends Panel implements ActionListener, MouseListener {
// The color of the border around the entire TabSplitter
private Color borderColor = null;
// The rectangle containing the +/-
private Rectangle bothRect;
// The number of the leftmost/rightmost visible tabs
private int firstVisible = 0;
private int lastVisible = 0;
// USed for double-buffering
private transient Graphics g1;
private transient Image image;
// The amount of overlap in the tabs
private int hslop = 4;
// The popup menu
private PopupMenu popupMenu = null;
// Used to determine if we need to reallocate the offscreen buffer
private int lastH = 0;
private int lastW = 0;
// The directional arrows
protected transient Polygon leftArrow;
protected transient Polygon rightArrow;
// The number of the currently-selected tab
private int selected = 0;
// The background color behind the tabs
private Color tabBackground = null;
// The colors to paint the tabs
private Color[] tabColors = null;
// The tab polygons
private Vector tabs;
// The text to display in the tabs
private String[] tabText = null;
// Are there more tabs than will fit?
private boolean tooManyTabs = false;
private int vslop = 4;
// The menu items used to display the names of the tabs on the popup menu
private MenuItem tabMenuItems[];
private Font currentFont;
private Font boldFont;
private FontMetrics fm;
private FontMetrics boldfm;
private int h;
protected boolean leftEnabled=false;
protected boolean rightEnabled=false;
private Hashtable explicitTabText = new Hashtable();
protected transient java.util.Vector aTabSelectionListener = null;
/** Constructor for the TabPanel */
public TabPanel() {
super();
addMouseListener(this);
tabs = new Vector();
setBackground(Color.lightGray);
setLayout(new CardLayout());
popupMenu = new PopupMenu("TabPanel");
add(popupMenu);
}
/** Handle the popup menu item selections
* @param e (java.awt.event.ActionEvent) -- the event that was fired to us
*/
public void actionPerformed(ActionEvent e) {
// walk through the list of menu items
// if the action came from one of them, show the
// corresponding tab component
for(int i = tabMenuItems.length-1; i > -1; i--)
if (e.getSource() == tabMenuItems[i]) {
showPhysicalTab(i);
break;
}
}
/** Adds a component to the TabPanel
* @param comp (Component) -- the component to be added
* @param constraints (Object) -- constraints on the component
* @param index (int) -- at which position will the component be added (-1 means at end)
*/
protected void addImpl(Component comp, Object constraints, int index) {
// if no constraints were passed in, use getName()
if (constraints == null)
constraints = comp.getName();
// The constraint must be a String
else if (!(constraints instanceof String))
throw new IllegalArgumentException("Constraint for add must be a String");
// If we have a String constaint _other_than_ the component's getName(),
// save it as an explicit tab text and use getName() as the constraint
else if (constraints != comp.getName()) {
explicitTabText.put(comp, constraints);
constraints = comp.getName();
}
// Add the component to the panel
super.addImpl(comp, constraints, index);
// if the bean is being displayed for a designer, force a repaint()
if (java.beans.Beans.isDesignTime())
repaint();
}
/** Add a listener who cares about tab selections
* @param newListener (TabSelectionListener) -- the component who cares...
*/
public void addTabSelectionListener(TabSelectionListener newListener) {
// lazy instantiation of the listener list...
if (aTabSelectionListener == null) {
aTabSelectionListener = new java.util.Vector();
};
// add the sucker to the list of people to inform
aTabSelectionListener.addElement(newListener);
}
/** Determines which text will be displayed in the tabs of the Tab panel.
* The text for each tab is determined as follows:
* <pre>
* If an explicit text were passed to add(), that text is used
* (note if the text happens to have the same value as that component's
* getName() call, it is not considered an explicit text)
* else if the component implements TabNamedComponent
* call its getTabName() method to determine the text
* else if the tabText[] propery was set and the
* text for that component is non-null
* use the tabText[tab number]
* else
* call getName() as a "last resort"
* </pre>
*
* <p>Note that this method should be used to figure out the tab text, <em>not</em>
* <tt>getTabText()</tt>, as <tt>getTabText()</tt> only gets the
* <tt>tabText[]</tt> property.
*
* @return An array of Strings that will appear on the tabs.
* @see #getTabText
* @see #setTabText
*/
public String[] determineTabText() {
int numComponents = getComponentCount();
// make a new array and assign values for undefined components
String names[] = new String[numComponents];
Component comps[] = getComponents();
for(int i=0;i < numComponents; i++) {
names[i] = (String)explicitTabText.get(comps[i]);
if (names[i] == null && comps[i] instanceof TabNamedComponent)
names[i] = ((TabNamedComponent)comps[i]).getTabName();
if (names[i] == null && tabText != null) {
int pos = getPosition(comps[i]);
if (pos < tabText.length)
names[i] = tabText[pos];
}
if (names[i] == null)
names[i] = comps[i].getName();
}
return names;
}
protected void determineVisible() {
if (fm == null) return; // hasn't been painted yet...
int startOfBothRect = getSize().width-26;
String tabText[] = determineTabText();
Component comp[] = getComponents();
int compCount = getComponentCount();
lastVisible = compCount-1; // assume they all fit...
tooManyTabs = (firstVisible != 0);
int tempXOff = 8;
for(int num=firstVisible; num<compCount; num++) {
String text = tabText[num];
int textWidth = (num==selected)?
boldfm.stringWidth(text) :
fm.stringWidth(text);
tempXOff += 28 + (hslop*2) + textWidth;
if (tempXOff > startOfBothRect) {
rightEnabled = true;
tooManyTabs = true;
if (num > firstVisible)
lastVisible = num-1;
else
lastVisible = num;
break;
}
tempXOff -= 14;
}
}
/** Draws the tabs at the top of the tab panel
* @param g (Graphics) -- the graphics context into which tabs are drawn
*/
protected void drawTabs(Graphics g) {
// Determine the text to put in the tabs
String tabText[] = determineTabText();
rightEnabled = false; // assume we don't need the right arrow
Dimension dim = getSize(); // get the size of the panel
setupTabPolygons(); // create the polygons for tab drawing/location test
// get a list of all the panels contained in the TabSplitter
Component comp[] = getComponents();
int compCount = getComponentCount();
if (compCount == 0) return; // if none, just get out
// lastVisible = compCount-1; // assume they all fit...
// if the first visible tab is not the first tab,
// force us to use the left/right arrows
// tooManyTabs = (firstVisible != 0);
// for each tab that is visible on the screen
Color tabColors[] = getTabColors();
for(int num=compCount-1;num>firstVisible-2;num--) {
int tabNum;
// draw the selected tab _last_ so it will appear on top
if (num == firstVisible-1) {
if (selected < firstVisible) break;
tabNum = selected;
g.setFont(boldFont);
}
else if (num == selected) continue;
else tabNum = num;
// choose the color for the tab
Color tabColor;
if (tabColors == null || tabColors.length == 0 ||
tabColors[tabNum % tabColors.length]==null)
tabColor = Color.lightGray; // default tab color
else
tabColor = tabColors[tabNum % tabColors.length];
g.setColor(tabColor);
// draw the polygon
Polygon p = (Polygon)tabs.elementAt(tabNum-firstVisible);
g.fillPolygon(p);
// draw hilites around that polygon
int x[] = p.xpoints;
int y[] = p.ypoints;
g.drawLine(x[0],y[0],x[11],y[11]);
g.setColor(tabColor.darker());
int i;
for(i=10;i>7;i--)
g.drawLine(x[i],y[i],x[i+1],y[i+1]);
g.setColor(tabColor.brighter());
for(i=0;i<5;i++) {
g.drawLine(x[i],y[i],x[i+1],y[i+1]);
if (tabNum == selected)
g.drawLine(x[11-i]-1,y[11-i],x[11-i-1]-1,y[11-i-1]);
}
g.drawLine(x[5],y[5],x[6],y[6]);
g.drawLine(x[6],y[6],x[7],y[7]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -