I wanted my application to look like eclipse. JGoodies delivers a good part of the looks. Except for the nice tabs. So I decided to start building it myself. Aided by the following very useful example: http://blog.elevenworks.com/?p=4
Note that this is a work in progress!!
First I subclassed JTabbedPane:
package nl.boplicity.swing; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.AbstractAction; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JTabbedPane; import nl.boplicity.bt.orderbuilder.workbench.ui.Editor; import nl.boplicity.swing.plaf.basic.EclipseTabbedPaneUI; /** * Eclipse style tabbedpane with elipse-look tabs and popup menu on tabs. * * FIXME: save dirty tabs first * * @author kees * @date 9-feb-2006 * */ public class EclipseTabbedPane extends JTabbedPane { private static final long serialVersionUID = 1176020466013529902L; private JPopupMenu popupMenu; private Integer selectedTabIndex; public EclipseTabbedPane() { super(); setUI(new EclipseTabbedPaneUI()); createPopupMenu(); addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent mouseEvent) { EclipseTabbedPane.this.mouseReleased(mouseEvent); } }); } private void mouseReleased(MouseEvent mouseEvent) { if (mouseEvent.isPopupTrigger()) { selectedTabIndex = indexAtLocation(mouseEvent.getX(), mouseEvent.getY()); // Only show for top row if (getTabPlacement() == JTabbedPane.TOP) { popupMenu.show(this, mouseEvent.getX(), mouseEvent.getY()); } } } private JPopupMenu createPopupMenu() { popupMenu = new JPopupMenu(); popupMenu.add(new CloseAction("Close")); popupMenu.add(new CloseOthersAction("Close Others")); popupMenu.add(new CloseAllAction("Close All")); return popupMenu; } private class CloseAction extends AbstractAction { private static final long serialVersionUID = -2625928077474199856L; public CloseAction(String name) { super(name); } public void actionPerformed(ActionEvent actionEvent) { closeTab(selectedTabIndex); } } private class CloseOthersAction extends AbstractAction { private static final long serialVersionUID = -2625928077474199856L; public CloseOthersAction(String name) { super(name); } public void actionPerformed(ActionEvent actionEvent) { // First remove higher indexes int tabCount = getTabCount(); if (selectedTabIndex < tabCount - 1) { for (int i = selectedTabIndex + 1; i < tabCount; i++) { closeTab(selectedTabIndex + 1); } } if (selectedTabIndex > 0) { for (int i = 0; i < selectedTabIndex; i++) { closeTab(0); } } } } private class CloseAllAction extends AbstractAction { private static final long serialVersionUID = -2625928077474199856L; public CloseAllAction(String name) { super(name); } public void actionPerformed(ActionEvent actionEvent) { int tabCount = getTabCount(); for (int i = 0; i < tabCount; i++) { closeTab(0); } } } }
The icing on the cake is created by a custom look and feel:
package nl.boplicity.swing.plaf.basic; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Paint; import java.awt.Rectangle; import javax.swing.Icon; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicTabbedPaneUI; /** * Implements the Eclipse-style tabs. * * <ul> * <li>Border turns blue it the pane has focus, white if not.</li> * <li>Selected tab is blue.</li> * <li>A close button is visible on the right if the tab is selected, is shows up in white when * the mouse hovers over an unslected tab. It turns red if the mouse hovers over * the selected tab's close button.</li> * <li>The tab displays an icon representing the content of the panel on the left * (Default tabbed pane functionality).</li> * </ul> * * Credits:<br/> * Jon Lipsky @see http://blog.elevenworks.com/?p=4<br/> * * TODO: create close buttons * TODO: shrink size of tabs if the bar is full * TODO: add eclipse style dropdown if tab bar is full instead of left-right buttons * * FIXME: right and bottom edges are not painted * FIXME: for now the tabbed pane relies on the pane it is contained in to * have a border. * * @author kees * @date 17-jan-2006 * */ public class EclipseTabbedPaneUI extends BasicTabbedPaneUI { private final Color SELECTED_TAB_COLOR = new Color(10, 36, 106); /** * FIXME: selected border has rounded top corners * * @see javax.swing.plaf.basic.BasicTabbedPaneUI#paintTabBorder(java.awt.Graphics, int, int, int, int, int, int, boolean) */ @Override protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { g.setColor(Color.GRAY); if (tabPlacement == BOTTOM) { g.drawLine(x, y + h, x + w, y + h); } // right g.drawLine(x + w - 1, y, x + w - 1, y + h); if (tabPlacement == TOP) { // And a white line to the left and top g.setColor(Color.WHITE); g.drawLine(x, y, x, y + h); g.drawLine(x, y, x + w - 2, y); } if (tabPlacement == BOTTOM && isSelected) { g.setColor(Color.WHITE); // Top g.drawLine(x + 1, y + 1, x + 1, y + h); // Right g.drawLine(x + w - 2, y, x + w - 2, y + h); // Left g.drawLine(x + 1, y + 1, x + w - 2, y + 1); // Bottom g.drawLine(x + 1, y + h - 1, x + w - 2, y + h - 1); } } /** * Give selected tab blue color with a gradient!!. * * FIXME: with Plastic L&F the unselected background is too dark * * @see javax.swing.plaf.basic.BasicTabbedPaneUI#paintTabBackground(java.awt.Graphics, int, int, int, int, int, int, boolean) */ @Override protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { Color color = UIManager.getColor("control"); if (isSelected) { if (tabPlacement == TOP) { Graphics2D g2 = (Graphics2D)g; Paint storedPaint = g2.getPaint(); g2.setPaint(new GradientPaint(x, y, SELECTED_TAB_COLOR, x + w, y + h, color)); g2.fillRect(x, y, w, h); g2.setPaint(storedPaint); } } else { g.setColor(color); g.fillRect(x, y, w - 1, h); } } /** * Do not paint a focus indicator. * * @see javax.swing.plaf.basic.BasicTabbedPaneUI#paintFocusIndicator(java.awt.Graphics, int, java.awt.Rectangle[], int, java.awt.Rectangle, java.awt.Rectangle, boolean) */ @Override protected void paintFocusIndicator(Graphics arg0, int arg1, Rectangle[] arg2, int arg3, Rectangle arg4, Rectangle arg5, boolean arg6) { // Leave it } /** * We do not want the tab to "lift up" when it is selected. * * @see javax.swing.plaf.basic.BasicTabbedPaneUI#installDefaults() */ @Override protected void installDefaults() { super.installDefaults(); tabAreaInsets = new Insets(0, 0, 0, 0); selectedTabPadInsets = new Insets(0, 0, 0, 0); contentBorderInsets = new Insets(1, 0, 0, 0); } /** * Nor do we want the label to move. */ @Override protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected) { return 0; } /** * Increase the tab height a bit */ @Override protected int calculateTabHeight(int tabPlacement, int tabIndex, int fontHeight) { return fontHeight + 10; } @Override protected void layoutLabel(int arg0, FontMetrics arg1, int arg2, String arg3, Icon arg4, Rectangle arg5, Rectangle arg6, Rectangle arg7, boolean arg8) { super.layoutLabel(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } /** * Selected labels have a white color. * * @see javax.swing.plaf.basic.BasicTabbedPaneUI#paintText(java.awt.Graphics, int, java.awt.Font, java.awt.FontMetrics, int, java.lang.String, java.awt.Rectangle, boolean) */ @Override protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { if (isSelected && tabPlacement == TOP) { g.setColor(Color.WHITE); } else { g.setColor(Color.BLACK); } // HACK: Force painting of Tahoma - Plastic L&F renders a big Arial Font tabFont = new Font("Tahoma", Font.PLAIN, 11); g.setFont(tabFont); g.drawString(title, textRect.x, textRect.y + metrics.getAscent()); } @Override protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { if (selectedIndex != -1 && tabPlacement == TOP) { g.setColor(Color.GRAY); g.drawLine(x, y, x + w, y); } } @Override protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { g.setColor(Color.GRAY); g.drawLine(x, y + h, x + w, y + h); } @Override protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { // do nothingx, y, x, y + h); } @Override protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) { // do nothing } }
Labels
(None)