像Netbeans这样的另一个动作内部的动作

时间:2016-04-01 09:29:48

标签: java netbeans

我需要找到在Netbeans使用Run Main Project图标的其他操作中显示多个操作的方法。

您可以看到默认操作Run Main Project,如果您点击绿色播放图标旁边的小箭头,则可以选择Run等特定操作。

我正在检查Netbeans的代码,但我无法在我的应用程序中找到代码。

2 个答案:

答案 0 :(得分:2)

我也一直在寻找像样的 JSplitButton,但我发现作为独立组件的所有东西都令人失望。

MadProgrammer 的回答看起来很有希望,但对我来说效果不佳。我不是 100% 确定它可能是由什么原因引起的,无论是设计原因还是我使用的 L&F,但提供的组件存在焦点问题。具体来说,弹出窗口的项目没有显示任何悬停指示器,表明它们没有获得焦点。同样在点击弹出窗口中的项目时弹出窗口没有自行关闭。

无论如何,我重写了部分组件并使其使用 JPopupMenu 而不是自定义 JFrame,以避免自己处理焦点。组件集的弹出菜单使用 JComponent.setComponentPopupMenu() 作为其弹出菜单,然后在单击下拉箭头时调用弹出菜单。这也使得可以右键单击按钮直接显示弹出窗口。

Component image

弹出窗口具有焦点并且表现得像一个普通的 JPopupMenu,支持添加分隔符之类的东西。

注意:图像中使用的 L&F 是 flatlaf


可以使用 addActionListener() 或通过调用 setAction() 使用操作来像普通 JButton 一样设置按钮的默认操作。

SplitButton btn = new SplitButton("Click me");
btn.addActionListener((e) -> {
    System.out.println("Button clicked");
});

SplitButton btn2 = new SplitButton(new AbstractAction("Click me") {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button clicked");
    }
});

可以单独创建弹出菜单,然后使用 setPopupMenu() 将其分配给按钮,或者您可以将单个项目作为操作添加到菜单中,而无需使用 addAction 自己创建addActionAt

JPopupMenu popup = new JPopupMenu();
popup.add(new JMenuItem("A popup option"));
popup.add(new JMenuItem("JMenuItem with icon", Icons.deleteBin));
popup.addSeparator();
btn.setPopupMenu(popup);
    
btn.addAction(new AbstractAction("Or don't", Icons.alert) {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Or don't clicked");
    }
});
btn.addAction(new AbstractAction("Click me in a different way") {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Click me in a different way clicked");
    }
});

只需使用getPopupMenu()即可检索弹出菜单。


完整代码

再次,由 MadProgrammer 和他从谁那里得到的原创:D

/**
 * A swing split button implementation.
 * A JButton that has an additional section with an arrow icon on the right that when clicked
 * shows a JPopupMenu that is positioned flush with the button.
 * 
 * The implementation sets the buttons pop-up menu using setComponentPopupMenu()
 * meaning that in addition to clicking the drop-down arrow, user can also right click
 * the button to open the pop-up menu.
 * 
 * Author: DUDSS - 21.02.2020
 * I modified the button to use a JPopupMenu instead of a custom JFrame to avoid hacky
 * focus workarounds and fix focus issues.
 * 
 * Credit:
 * Modified version of a split button by MadProgrammer.
 * https://stackoverflow.com/questions/36352707/actions-inside-of-another-action-like-netbeans
 * It's original author seems to be unknown.
 *
 */
public class SplitButton extends JButton {
    private int separatorSpacing = 4;
    private int splitWidth = 22;
    private int arrowSize = 8;
    private boolean onSplit;
    private Rectangle splitRectangle;
    private boolean alwaysDropDown;
    private Color arrowColor = Color.BLACK;
    private Color disabledArrowColor = Color.GRAY;
    private Image image;
    private MouseHandler mouseHandler;
    private boolean toolBarButton;
    
    private JPopupMenu jpopupMenu;

    /**
     * Creates a button with initial text and an icon.
     *
     * @param text the text of the button
     * @param icon the Icon image to display on the button
     */
    public SplitButton() {
        super();
        addMouseMotionListener(getMouseHandler());
        addMouseListener(getMouseHandler());
        // Default for no "default" action...
        setAlwaysDropDown(true);

        InputMap im = getInputMap(WHEN_FOCUSED);
        ActionMap am = getActionMap();

        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "PopupMenu.close");
        am.put("PopupMenu.close", new ClosePopupAction());
    }
    
    public SplitButton(Action defaultAction) {
        this();
        setAction(defaultAction);
    }
    
    public SplitButton(Action defaultAction, JPopupMenu popup) {
        this();
        setAction(defaultAction);
        setPopupMenu(popup);
    }
    
    public SplitButton(Action defaultAction, Action... actions) {
        this();
        setAction(defaultAction);
        for (Action a : actions) {
            addAction(a);
        }
    }
    
    public SplitButton(String text) {
        this();
        setText(text);
    }
    
    public SplitButton(String text, Icon icon) {
        this();
        setText(text);
        setIcon(icon);
    }
    
    public SplitButton(String text, JPopupMenu popup) {
        this();
        setText(text);
        setPopupMenu(popup);
    }
    
    public SplitButton(String text, Icon icon, JPopupMenu popup) {
        this();
        setText(text);
        setIcon(icon);
        setPopupMenu(popup);
    }

    /**
     * Creates a pre-configured button suitable for being used on a JToolBar
     *
     * @param defaultAction
     * @param actions
     * @return
     */
    public static SplitButton createToolBarButton(Action defaultAction, Action... actions) {
        SplitButton btn = new SplitButton(defaultAction, actions);
        btn.configureForToolBar();
        return btn;
    }

    /**
     * Creates a pre-configured "options only" button suitable for being used on
     * a JToolBar
     *
     * @param text
     * @param icon
     * @param actions
     * @return
     */
    public static SplitButton createToolBarButton(String text, Icon icon, JPopupMenu popupMenu) {
        SplitButton btn = new SplitButton(text, icon);
        btn.setPopupMenu(popupMenu);
        btn.setToolTipText(text);
        btn.configureForToolBar();
        return btn;
    }

    @Override
    public void addActionListener(ActionListener l) {
        if (l != null) {
             setAlwaysDropDown(false);
        }
        super.addActionListener(l);
    }
    
    @Override
    public void setAction(Action a) {
        super.setAction(a);
        if (a != null) {
            setAlwaysDropDown(false);
        }
    }

    public void addActionAt(Action a, int index) {
        getPopupMenu().insert(a, index);
    }

    public void addAction(Action a) {
        getPopupMenu().add(a);
    }

    public void setPopupMenu(JPopupMenu popup) {
        jpopupMenu = popup;
        this.setComponentPopupMenu(popup);
    }

    /**
     * Returns the buttons popup menu.
     *
     * @return
     */
    public JPopupMenu getPopupMenu() {
        if (jpopupMenu == null) {
            jpopupMenu = new JPopupMenu();
        }
        return jpopupMenu;
    }

    /**
     * Used to determine if the button is begin configured for use on a tool bar
     *
     * @return
     */
    public boolean isToolBarButton() {
        return toolBarButton;
    }

    /**
     * Configures this button for use on a tool bar...
     */
    public void configureForToolBar() {
        toolBarButton = true;
        if (getIcon() != null) {
            setHideActionText(true);
        }
        setHorizontalTextPosition(JButton.CENTER);
        setVerticalTextPosition(JButton.BOTTOM);
        setFocusable(false);
    }

    protected MouseHandler getMouseHandler() {
        if (mouseHandler == null) {
            mouseHandler = new MouseHandler();
        }
        return mouseHandler;
    }
    
    protected int getOptionsCount() {
        return getPopupMenu().getComponentCount();
    }

    /*protected void addActionAt(Action action, int index) {
        if (index < 0 || index >= getOptionsCount()) {
            getPopupWindow().add(createMenuItem(action));
        } else {
            getPopupWindow().add(createMenuItem(action), index);
        }
    }*/

    /*protected void removeAction(Action action) {
        AbstractButton btn = getButtonFor(action);
        if (btn != null) {
            getPopupWindow().remove(btn);
        }
    }*/

    @Override
    public Insets getInsets() {
        Insets insets = (Insets) super.getInsets().clone();
        insets.right += splitWidth;
        return insets;
    }

    @Override
    public Insets getInsets(Insets insets) {
        Insets insets1 = getInsets();
        insets.left = insets1.left;
        insets.right = insets1.right;
        insets.bottom = insets1.bottom;
        insets.top = insets1.top;
        return insets1;
    }

    protected void closePopupMenu() {
        getPopupMenu().setVisible(false);
    }

    protected void showPopupMenu() {
        if (getOptionsCount() > 0) {
            JPopupMenu menu = getPopupMenu();
            menu.setVisible(true); //Necessary to calculate pop-up menu width the first time it's displayed.
            menu.show(this, (getWidth() - menu.getWidth()), getHeight());
        }
    }

    /**
     * Returns the separatorSpacing. Separator spacing is the space above and
     * below the separator( the line drawn when you hover your mouse over the
     * split part of the button).
     *
     * @return separatorSpacingimage = null; //to repaint the image with the new
     * size
     */
    public int getSeparatorSpacing() {
        return separatorSpacing;
    }

    /**
     * Sets the separatorSpacing.Separator spacing is the space above and below
     * the separator( the line drawn when you hover your mouse over the split
     * part of the button).
     *
     * @param spacing
     */
    public void setSeparatorSpacing(int spacing) {
        if (spacing != separatorSpacing && spacing >= 0) {
            int old = separatorSpacing;
            this.separatorSpacing = spacing;
            image = null;
            firePropertyChange("separatorSpacing", old, separatorSpacing);
            revalidate();
            repaint();
        }
    }

    /**
     * Show the dropdown menu, if attached, even if the button part is clicked.
     *
     * @return true if alwaysDropdown, false otherwise.
     */
    public boolean isAlwaysDropDown() {
        return alwaysDropDown;
    }

    /**
     * Show the dropdown menu, if attached, even if the button part is clicked.
     *
     * If true, this will prevent the button from raising any actionPerformed
     * events for itself
     *
     * @param value true to show the attached dropdown even if the button part
     * is clicked, false otherwise
     */
    public void setAlwaysDropDown(boolean value) {
        if (alwaysDropDown != value) {
            this.alwaysDropDown = value;
            firePropertyChange("alwaysDropDown", !alwaysDropDown, alwaysDropDown);
        }
    }

    /**
     * Gets the color of the arrow.
     *
     * @return arrowColor
     */
    public Color getArrowColor() {
        return arrowColor;
    }

    /**
     * Set the arrow color.
     *
     * @param color
     */
    public void setArrowColor(Color color) {
        if (arrowColor != color) {
            Color old = arrowColor;
            this.arrowColor = color;
            image = null;
            firePropertyChange("arrowColor", old, arrowColor);
            repaint();
        }
    }

    /**
     * gets the disabled arrow color
     *
     * @return disabledArrowColor color of the arrow if no popup attached.
     */
    public Color getDisabledArrowColor() {
        return disabledArrowColor;
    }

    /**
     * sets the disabled arrow color
     *
     * @param color color of the arrow if no popup attached.
     */
    public void setDisabledArrowColor(Color color) {
        if (disabledArrowColor != color) {
            Color old = disabledArrowColor;
            this.disabledArrowColor = color;
            image = null; //to repaint the image with the new color
            firePropertyChange("disabledArrowColor", old, disabledArrowColor);
        }
    }

    /**
     * Splitwidth is the width of the split part of the button.
     *
     * @return splitWidth
     */
    public int getSplitWidth() {
        return splitWidth;
    }

    /**
     * Splitwidth is the width of the split part of the button.
     *
     * @param width
     */
    public void setSplitWidth(int width) {
        if (splitWidth != width) {
            int old = splitWidth;
            this.splitWidth = width;
            firePropertyChange("splitWidth", old, splitWidth);
            revalidate();
            repaint();
        }
    }

    /**
     * gets the size of the arrow.
     *
     * @return size of the arrow
     */
    public int getArrowSize() {
        return arrowSize;
    }

    /**
     * sets the size of the arrow
     *
     * @param size
     */
    public void setArrowSize(int size) {
        if (arrowSize != size) {
            int old = arrowSize;
            this.arrowSize = size;
            image = null; //to repaint the image with the new size
            firePropertyChange("setArrowSize", old, arrowSize);
            revalidate();
            repaint();
        }
    }

    /**
     * Gets the image to be drawn in the split part. If no is set, a new image
     * is created with the triangle.
     *
     * @return image
     */
    public Image getImage() {
        if (image == null) {
            Graphics2D g = null;
            BufferedImage img = new BufferedImage(arrowSize, arrowSize, BufferedImage.TYPE_INT_RGB);
            g = (Graphics2D) img.createGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, img.getWidth(), img.getHeight());
            g.setColor(jpopupMenu != null ? arrowColor : disabledArrowColor);
            //this creates a triangle facing right >
            g.fillPolygon(new int[]{0, 0, arrowSize / 2}, new int[]{0, arrowSize, arrowSize / 2}, 3);
            g.dispose();
            //rotate it to face downwards
            img = rotate(img, 90);
            BufferedImage dimg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
            g = (Graphics2D) dimg.createGraphics();
            g.setComposite(AlphaComposite.Src);
            g.drawImage(img, null, 0, 0);
            g.dispose();
            for (int i = 0; i < dimg.getHeight(); i++) {
                for (int j = 0; j < dimg.getWidth(); j++) {
                    if (dimg.getRGB(j, i) == Color.WHITE.getRGB()) {
                        dimg.setRGB(j, i, 0x8F1C1C);
                    }
                }
            }

            image = Toolkit.getDefaultToolkit().createImage(dimg.getSource());
        }
        return image;
    }

    /**
     *
     * @param g
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //Graphics gClone = g.create();//EDIT: Hervé Guillaume
        Color oldColor = g.getColor();
        splitRectangle = new Rectangle(getWidth() - splitWidth, 0, splitWidth, getHeight());
        g.translate(splitRectangle.x, splitRectangle.y);
        int mh = getHeight() / 2;
        int mw = splitWidth / 2;
        g.drawImage(getImage(), mw - arrowSize / 2, mh + 2 - arrowSize / 2, null);
        if (!alwaysDropDown) {
            if (getModel().isRollover() || isFocusable()) {
                g.setColor(UIManager.getLookAndFeelDefaults().getColor("Button.background"));
                g.drawLine(1, separatorSpacing + 2, 1, getHeight() - separatorSpacing - 2);
                g.setColor(UIManager.getLookAndFeelDefaults().getColor("Button.shadow"));
                g.drawLine(2, separatorSpacing + 2, 2, getHeight() - separatorSpacing - 2);
            }
        }
        g.setColor(oldColor);
        g.translate(-splitRectangle.x, -splitRectangle.y);
    }

    /**
     * Rotates the given image with the specified angle.
     *
     * @param img image to rotate
     * @param angle angle of rotation
     * @return rotated image
     */
    private BufferedImage rotate(BufferedImage img, int angle) {
        int w = img.getWidth();
        int h = img.getHeight();
        BufferedImage dimg = dimg = new BufferedImage(w, h, img.getType());
        Graphics2D g = dimg.createGraphics();
        g.rotate(Math.toRadians(angle), w / 2, h / 2);
        g.drawImage(img, null, 0, 0);
        return dimg;
    }

    @Override
    protected void fireActionPerformed(ActionEvent event) {
        // This is a little bit of a nasty trick.  Basically this is where
        // we try and decide if the buttons "default" action should
        // be fired or not.  We don't want it firing if the button
        // is in "options only" mode or the user clicked on
        // on the "drop down arrow"....
        if (onSplit || isAlwaysDropDown()) {
            showPopupMenu();
        } else {
            super.fireActionPerformed(event);

        }
    }

    protected class MouseHandler extends MouseAdapter {
        @Override
        public void mouseExited(MouseEvent e) {
            onSplit = false;
            repaint(splitRectangle);
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            if (splitRectangle.contains(e.getPoint())) {
                onSplit = true;
            } else {
                onSplit = false;
            }
            repaint(splitRectangle);
        }
    }

    protected class ClosePopupAction extends AbstractAction {
        @Override
        public void actionPerformed(ActionEvent e) {
            closePopupMenu();
        }
    }
}

答案 1 :(得分:1)

啊,(其中一个)UI组件的圣杯,一个分裂按钮。多年来,我一直试图找到一个在多种外观和感觉下表现良好且惨淡失败的产品。

许多人使用多个按钮或只是使用JComboBox

像许多事情一样,我偶然发现了一个做得很好的事情,但我不得不修改以满足我的需要,不幸的是,我不记得原版或作者,对不起。 (如果您认为此代码基于您的代码,请留下评论并附上原始链接,我将评估并提供相应的信用)

SplitButton

基本上,如果你点击按钮,它将运行&#34;默认&#34;动作(香蕉),否则你可以选择其中一个子元素,它将执行它

public class SplitButton extends JButton {

    private int separatorSpacing = 4;
    private int splitWidth = 22;
    private int arrowSize = 8;
    private boolean onSplit;
    private Rectangle splitRectangle;
    private JFrame popupMenu;
    private boolean alwaysDropDown;
    private Color arrowColor = Color.BLACK;
    private Color disabledArrowColor = Color.GRAY;
    private Image image;
    private MouseHandler mouseHandler;
    private boolean toolBarButton;

    private PopupWindowEventHandler popupWindowEventHandler;

    /**
     * Creates a button with initial text and an icon.
     *
     * @param text the text of the button
     * @param icon the Icon image to display on the button
     */
    public SplitButton() {
        super();
        addMouseMotionListener(getMouseHandler());
        addMouseListener(getMouseHandler());
        // Default for no "default" action...
        setAlwaysDropDown(true);

        InputMap im = getInputMap(WHEN_FOCUSED);
        ActionMap am = getActionMap();

        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "PopupMenu.close");
        am.put("PopupMenu.close", new ClosePopupAction());

    }

    public SplitButton(Action defaultAction, Action... actions) {
        this();
        setAction(defaultAction);
        for (Action action : actions) {
            addAction(action);
        }
    }

    public SplitButton(String text, Icon icon, Action... actions) {
        this((Action) null, actions);
        setText(text);
        setIcon(icon);
    }

    public SplitButton(String text, Action... actions) {
        this((Action) null, actions);
        setText(text);
    }

    public JSplitButton(Icon icon, Action... actions) {
        this((Action) null, actions);
        setIcon(icon);
    }

    @Override
    public void setAction(Action a) {
        super.setAction(a);
        if (a != null) {
            setAlwaysDropDown(false);
        }
    }

    /**
     * Creates a pre-configured button suitable for being used on a JToolBar
     *
     * @param defaultAction
     * @param actions
     * @return
     */
    public static SplitButton createToolBarButton(Action defaultAction, Action... actions) {
        JSplitButton btn = new JSplitButton(defaultAction, actions);
        btn.configureForToolBar();
        return btn;
    }

    /**
     * Creates a pre-configured "options only" button suitable for being used on
     * a JToolBar
     *
     * @param text
     * @param icon
     * @param actions
     * @return
     */
    public static SplitButton createToolBarButton(String text, Icon icon, Action... actions) {
        JSplitButton btn = new JSplitButton(icon, actions);
        btn.setToolTipText(text);
        btn.configureForToolBar();
        return btn;
    }

    /**
     * Used to determine if the button is begin configured for use on a tool bar
     *
     * @return
     */
    public boolean isToolBarButton() {
        return toolBarButton;
    }

    /**
     * Configures this button for use on a tool bar...
     */
    public void configureForToolBar() {
        toolBarButton = true;
        if (getIcon() != null) {
            setHideActionText(true);
        }
        setHorizontalTextPosition(JButton.CENTER);
        setVerticalTextPosition(JButton.BOTTOM);
        setFocusable(false);
    }

    protected MouseHandler getMouseHandler() {
        if (mouseHandler == null) {
            mouseHandler = new MouseHandler();
        }
        return mouseHandler;
    }

    protected AbstractButton getButtonFor(Action action) {
        Container parent = ((JFrame) getPopupWindow()).getContentPane();
        AbstractButton btn = null;
        for (Component comp : parent.getComponents()) {
            if (comp instanceof AbstractButton) {
                Action childAction = ((AbstractButton) comp).getAction();
                if (action.equals(childAction)) {
                    btn = (AbstractButton) comp;
                    break;
                }
            }
        }

        return btn;
    }

    /**
     * Returns the index of the specified action within the popup window or -1
     * of it does not exist
     *
     * @param action
     * @return
     */
    public int indexOfAction(Action action) {
        Container parent = ((JFrame) getPopupWindow()).getContentPane();
        AbstractButton btn = getButtonFor(action);

        return btn == null ? -1 : parent.getComponentZOrder(btn);
    }

    /**
     * Adds the specified action to the popup menu...
     *
     * This simply calls getPopupWindow().add(action)
     *
     * @param action Add
     */
    public void addAction(Action action) {
        addActionAt(action, -1);
    }

    protected int getOptionsCount() {
        return ((JFrame) getPopupWindow()).getContentPane().getComponentCount();
    }

    protected void addActionAt(Action action, int index) {
        if (index < 0 || index >= getOptionsCount()) {
            getPopupWindow().add(createMenuItem(action));
        } else {
            getPopupWindow().add(createMenuItem(action), index);
        }
    }

    protected void removeAction(Action action) {
        AbstractButton btn = getButtonFor(action);
        if (btn != null) {
            getPopupWindow().remove(btn);
        }
    }

    /**
     * Creates a new JMenuItem from the supplied Action. This is used to
     * provided the ability for subclasses to either change the type of menu
     * item used by the button or add additional functionality (like listeners)
     * should they be required
     *
     * @param action
     * @return
     */
    protected JMenuItem createMenuItem(Action action) {
        return new JMenuItem(action);
    }

    @Override
    public Insets getInsets() {
        Insets insets = (Insets) super.getInsets().clone();
        insets.right += splitWidth;
        return insets;
    }

    @Override
    public Insets getInsets(Insets insets) {
        Insets insets1 = getInsets();
        insets.left = insets1.left;
        insets.right = insets1.right;
        insets.bottom = insets1.bottom;
        insets.top = insets1.top;
        return insets1;
    }

    /**
     * Returns the window that acts as the buttons popup window
     *
     * @return
     */
    public Window getPopupWindow() {
        if (popupMenu == null) {
            popupMenu = new JFrame();
            popupMenu.setFocusableWindowState(false);
            popupMenu.setUndecorated(true);
            popupMenu.setContentPane(createPopupWindowContentPane());
            popupMenu.setAlwaysOnTop(true);
            DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    String name = evt.getPropertyName();
                    if ("focusOwner".equalsIgnoreCase(name)
                            || "permanentFocusOwner".equalsIgnoreCase(name)
                            || "focusedWindow".equalsIgnoreCase(name)
                            || "activeWindow".equalsIgnoreCase(name)) {
                        Window focusedWindow = DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
                        if (!popupMenu.equals(focusedWindow)) {
                            closePopupWinodw();
                        }
                    }
                }
            });
        }
        return popupMenu;
    }

    protected Container createPopupWindowContentPane() {
        return new DefaultMenuPane();
    }

    protected void closePopupWinodw() {
        getPopupWindow().setVisible(false);
        if (popupWindowEventHandler != null) {
            Toolkit.getDefaultToolkit().removeAWTEventListener(popupWindowEventHandler);
        }
    }

    protected void showPopupWindow() {
        Window popup = getPopupWindow();
        popup.pack();
        Point pos = getLocationOnScreen();
        popup.setLocation(pos.x + (getWidth() - popup.getWidth()), pos.y + getHeight());
        popup.setVisible(true);

        if (popupWindowEventHandler == null) {
            popupWindowEventHandler = new PopupWindowEventHandler();
        }
        Toolkit.getDefaultToolkit().addAWTEventListener(popupWindowEventHandler, AWTEvent.MOUSE_EVENT_MASK);
    }

    /**
     * Returns the separatorSpacing. Separator spacing is the space above and
     * below the separator( the line drawn when you hover your mouse over the
     * split part of the button).
     *
     * @return separatorSpacingimage = null; //to repaint the image with the new
     * size
     */
    public int getSeparatorSpacing() {
        return separatorSpacing;
    }

    /**
     * Sets the separatorSpacing.Separator spacing is the space above and below
     * the separator( the line drawn when you hover your mouse over the split
     * part of the button).
     *
     * @param spacing
     */
    public void setSeparatorSpacing(int spacing) {
        if (spacing != separatorSpacing && spacing >= 0) {
            int old = separatorSpacing;
            this.separatorSpacing = spacing;
            image = null;
            firePropertyChange("separatorSpacing", old, separatorSpacing);
            revalidate();
            repaint();
        }
    }

    /**
     * Show the dropdown menu, if attached, even if the button part is clicked.
     *
     * @return true if alwaysDropdown, false otherwise.
     */
    public boolean isAlwaysDropDown() {
        return alwaysDropDown;
    }

    /**
     * Show the dropdown menu, if attached, even if the button part is clicked.
     *
     * If true, this will prevent the button from raising any actionPerformed
     * events for itself
     *
     * @param value true to show the attached dropdown even if the button part
     * is clicked, false otherwise
     */
    public void setAlwaysDropDown(boolean value) {
        if (alwaysDropDown != value) {
            this.alwaysDropDown = value;
            firePropertyChange("alwaysDropDown", !alwaysDropDown, alwaysDropDown);
        }
    }

    /**
     * Gets the color of the arrow.
     *
     * @return arrowColor
     */
    public Color getArrowColor() {
        return arrowColor;
    }

    /**
     * Set the arrow color.
     *
     * @param color
     */
    public void setArrowColor(Color color) {
        if (arrowColor != color) {
            Color old = arrowColor;
            this.arrowColor = color;
            image = null;
            firePropertyChange("arrowColor", old, arrowColor);
            repaint();
        }
    }

    /**
     * gets the disabled arrow color
     *
     * @return disabledArrowColor color of the arrow if no popup attached.
     */
    public Color getDisabledArrowColor() {
        return disabledArrowColor;
    }

    /**
     * sets the disabled arrow color
     *
     * @param color color of the arrow if no popup attached.
     */
    public void setDisabledArrowColor(Color color) {
        if (disabledArrowColor != color) {
            Color old = disabledArrowColor;
            this.disabledArrowColor = color;
            image = null; //to repaint the image with the new color
            firePropertyChange("disabledArrowColor", old, disabledArrowColor);
        }
    }

    /**
     * Splitwidth is the width of the split part of the button.
     *
     * @return splitWidth
     */
    public int getSplitWidth() {
        return splitWidth;
    }

    /**
     * Splitwidth is the width of the split part of the button.
     *
     * @param width
     */
    public void setSplitWidth(int width) {
        if (splitWidth != width) {
            int old = splitWidth;
            this.splitWidth = width;
            firePropertyChange("splitWidth", old, splitWidth);
            revalidate();
            repaint();
        }
    }

    /**
     * gets the size of the arrow.
     *
     * @return size of the arrow
     */
    public int getArrowSize() {
        return arrowSize;
    }

    /**
     * sets the size of the arrow
     *
     * @param size
     */
    public void setArrowSize(int size) {
        if (arrowSize != size) {
            int old = arrowSize;
            this.arrowSize = size;
            image = null; //to repaint the image with the new size
            firePropertyChange("setArrowSize", old, arrowSize);
            revalidate();
            repaint();
        }
    }

    /**
     * Gets the image to be drawn in the split part. If no is set, a new image
     * is created with the triangle.
     *
     * @return image
     */
    public Image getImage() {
        if (image == null) {
            Graphics2D g = null;
            BufferedImage img = new BufferedImage(arrowSize, arrowSize, BufferedImage.TYPE_INT_RGB);
            g = (Graphics2D) img.createGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, img.getWidth(), img.getHeight());
            g.setColor(popupMenu != null ? arrowColor : disabledArrowColor);
            //this creates a triangle facing right >
            g.fillPolygon(new int[]{0, 0, arrowSize / 2}, new int[]{0, arrowSize, arrowSize / 2}, 3);
            g.dispose();
            //rotate it to face downwards
            img = rotate(img, 90);
            BufferedImage dimg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
            g = (Graphics2D) dimg.createGraphics();
            g.setComposite(AlphaComposite.Src);
            g.drawImage(img, null, 0, 0);
            g.dispose();
            for (int i = 0; i < dimg.getHeight(); i++) {
                for (int j = 0; j < dimg.getWidth(); j++) {
                    if (dimg.getRGB(j, i) == Color.WHITE.getRGB()) {
                        dimg.setRGB(j, i, 0x8F1C1C);
                    }
                }
            }

            image = Toolkit.getDefaultToolkit().createImage(dimg.getSource());
        }
        return image;
    }

    /**
     *
     * @param g
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //Graphics gClone = g.create();//EDIT: Hervé Guillaume
        Color oldColor = g.getColor();
        splitRectangle = new Rectangle(getWidth() - splitWidth, 0, splitWidth, getHeight());
        g.translate(splitRectangle.x, splitRectangle.y);
        int mh = getHeight() / 2;
        int mw = splitWidth / 2;
        g.drawImage(getImage(), mw - arrowSize / 2, mh + 2 - arrowSize / 2, null);
        if (!alwaysDropDown) {
            if (getModel().isRollover() || isFocusable()) {
                g.setColor(UIManager.getLookAndFeelDefaults().getColor("Button.background"));
                g.drawLine(1, separatorSpacing + 2, 1, getHeight() - separatorSpacing - 2);
                g.setColor(UIManager.getLookAndFeelDefaults().getColor("Button.shadow"));
                g.drawLine(2, separatorSpacing + 2, 2, getHeight() - separatorSpacing - 2);
            }
        }
        g.setColor(oldColor);
        g.translate(-splitRectangle.x, -splitRectangle.y);
    }

    /**
     * Rotates the given image with the specified angle.
     *
     * @param img image to rotate
     * @param angle angle of rotation
     * @return rotated image
     */
    private BufferedImage rotate(BufferedImage img, int angle) {
        int w = img.getWidth();
        int h = img.getHeight();
        BufferedImage dimg = dimg = new BufferedImage(w, h, img.getType());
        Graphics2D g = dimg.createGraphics();
        g.rotate(Math.toRadians(angle), w / 2, h / 2);
        g.drawImage(img, null, 0, 0);
        return dimg;
    }

    @Override
    protected void fireActionPerformed(ActionEvent event) {
        // This is a little bit of a nasty trick.  Basically this is where
        // we try and decide if the buttons "default" action should
        // be fired or not.  We don't want it firing if the button
        // is in "options only" mode or the user clicked on
        // on the "drop down arrow"....
        if (onSplit || isAlwaysDropDown()) {
            showPopupWindow();
        } else {
            super.fireActionPerformed(event);

        }
    }

    protected class MouseHandler extends MouseAdapter {

        @Override
        public void mouseExited(MouseEvent e) {
            onSplit = false;
            repaint(splitRectangle);
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            if (splitRectangle.contains(e.getPoint())) {
                onSplit = true;
            } else {
                onSplit = false;
            }
            repaint(splitRectangle);
        }
    }

    protected class PopupWindowEventHandler implements AWTEventListener {

        @Override
        public void eventDispatched(AWTEvent event) {
            if (popupMenu.isVisible()) {
                switch (event.getID()) {
                    case MouseEvent.MOUSE_RELEASED:
                        Object source = event.getSource();
                        if (source instanceof Component) {
                            Window win = SwingUtilities.getWindowAncestor((Component) source);
                            if (!popupMenu.equals(win)) {
                                closePopupWinodw();
                            }
                        }
                        break;
                }
            }
        }

    }

    protected class ClosePopupAction extends AbstractAction {

        @Override
        public void actionPerformed(ActionEvent e) {
            closePopupWinodw();
        }

    }

    protected class DefaultMenuPane extends JPanel {

        public DefaultMenuPane() {
            setBorder(UIManager.getBorder("PopupMenu.border"));
            setBackground(UIManager.getColor("PopupMenu.background"));
            setLayout(new GridLayout(0, 1));
        }

    }

}

它会被配置为......

SplitButton btn = new SplitButton();
btn.setAction(new FruitAction("Banana", new BananaIcon(32, 32)));
btn.addAction(new FruitAction("Apple", new AppleIcon(32, 32)));
btn.addAction(new FruitAction("Black Berry", new BlackBerriesIcon(32, 32)));
btn.addAction(new FruitAction("Grapes", new GrapesIcon(32, 32)));
btn.addAction(new FruitAction("Peach", new PeachIcon(32, 32)));
btn.addAction(new FruitAction("Strewberry", new StrewberriesIcon(32, 32)));

而且,作为参考,水果动作看起来像......

public class FruitAction extends AbstractAction {

    public FruitAction(String text, Icon icon) {

        putValue(NAME, text);
        putValue(SMALL_ICON, icon);
        putValue(SHORT_DESCRIPTION, text);

    }

    @Override
    public void actionPerformed(ActionEvent e) {

        JOptionPane.showMessageDialog(null, "I am " + getValue(NAME), "Fruit", JOptionPane.INFORMATION_MESSAGE);

    }

}

这是使用基于自定义矢量的图标库,所以显然,我不会包括它,但它会让你知道如何配置它