带图像,文本,箭头和菜单的按钮

时间:2016-04-10 21:38:07

标签: java swing

我想创建一个按钮,其顶部有一个图标,角上有箭头。点击它后,会显示一个菜单。除箭头部分外,我能够实现以上所有目标。我知道我可以有一个图像文件,图标和箭头保存在一个png文件中。但是,我不想改变图标文件。这是我到目前为止的代码。

如何添加箭头(无论是以编程方式还是从其他箭头图像文件添加到按钮)

public class JButtonMenu extends JToggleButton {

    JPopupMenu popup;

    public JButtonMenu(ImageIcon img, String title, String []list) {
        super(name);
        this.popup = new JPopupMenu();
        this.buttonId = buttonId;
        this.setMenuList(list);  //This is another method 
        setIcon(img);
        setVerticalTextPosition(SwingConstants.TOP);
        setHorizontalTextPosition(SwingConstants.CENTER);
    }

    public void setMenuList(String[]list){
        if(list == null){
            return;
        }
        for(String item:list){
            popup.add(new JMenuItem(new AbstractAction(item) {
            public void actionPerformed(ActionEvent e) {
                JMenuItem menuItem = (JMenuItem)e.getSource();
                int index= popup.getComponentIndex(menuItem);
                menuItemListener.itemSelectedListener(buttonId,index, menuItem.getText());
            }
        }));
        }
    }
}

1 个答案:

答案 0 :(得分:1)

这基本上是this implementation of a split button的淡化版本,但它侧重于绘制额外图像的需要以及您需要实现的一些其他功能,以确保原始文本和图标是偏移准确。

Example split button

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                SplitButton btn = new SplitButton();
                btn.setText("This is a split button");

                JFrame frame = new JFrame("Testing");
                frame.setLayout(new GridBagLayout());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(btn);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SplitButton extends JButton {

        private int separatorSpacing = 4;
        private int splitWidth = 30;
        private int arrowSize = 8;

        private Rectangle splitRectangle;
        private Color arrowColor = Color.BLACK;
        private Color disabledArrowColor = Color.GRAY;
        private Image image;

        public SplitButton() {
            super();
        }

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

        /**
         * 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(isEnabled() ? 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 (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;
        }

    }

}

Swing有一个定义明确的文档绘制过程,为了执行自定义绘制,你需要在API的约束下工作,否则你最终会遇到问题。

请查看Painting in AWT and SwingPerforming Custom Painting了解详情