Netbeans等其他动作中的动作 [英] Actions inside of another action like Netbeans

查看:80
本文介绍了Netbeans等其他动作中的动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要找到一种方法来显示另一个动作(例如Netbeans带有Run Main Project图标)的几个动作.

I need to find the way to show several actions inside of another action like Netbeans does with Run Main Project icon.

您会看到有一个默认动作Run Main Project,如果您点击绿色播放图标旁边的小箭头,则可以选择特定的动作,例如Run.

You can see there is a default action Run Main Project and if you click in the little arrow next to the green play icon, you can select a specific action like Run .

我正在检查Netbeans的代码,但找不到在我的应用程序中实现此功能的代码.

I was checking the code of Netbeans but I can't find the code to make this in my application.

推荐答案

啊,UI组件的神圣之处之一,一个拆分按钮.多年来,我一直试图找到一种在多种外观和感觉下都能表现良好并且失败的案例.

Ah, (one of) the holy grails of UI components, a split button. Over a number of years I've tried to find one which would perform well under multiple look and feels and failed dismally.

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

Many used multiple buttons or just resorted to using a JComboBox

就像很多事情一样,我偶然发现了一个做得很好的东西,但是不幸的是,我不得不对其进行修改以满足自己的需求,对不起,我不记得它的原始版本或作者了. (如果您认为此代码基于您的代码,请在注释中附上原始代码的链接,我会进行评估并提供适当的信誉)

Like many things, I stumbled across one which was pretty well done, but which I had to modify to suit my needs, unfortunately, I don't remember the original version or author, sorry. (If you believe this code is based on yours, please leave a comment with a link to the original and I will evaluate and provide appropriate credit)

基本上,如果单击该按钮,它将运行默认"操作(香蕉),否则,您可以选择一个子元素并执行它

Basically, if you click the button, it will run the "default" action (Bananas) otherwise you can select one of the sub elements and it will execute it

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));
        }

    }

}

它将配置为类似...

It would be configured something like ...

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)));

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

And, for reference, the fruit action looks like...

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);

    }

}

这是使用基于自定义矢量的图标库,因此,显然,我不会包含它,但是它为您提供了如何配置它的想法

This is use a custom vector based icon library, so obviously, I won't be including that, but it gives you an idea of how to configure it

这篇关于Netbeans等其他动作中的动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆