复杂的按钮布局

3
我想实现一个看起来像这个按钮的按钮,但是外环要分成四部分,以便我有四个图像可以制作成按钮,中间的图像是用来制作中间按钮的。 为了将四个按钮分开,可以想象一个十字形或X形。如何布局按钮以实现此类组件?
我尝试使用BorderLayoutGridBagLayout,但由于swing按钮的矩形形状产生了太多空间,导致每个按钮图像之间的间隔过大,因此看起来不好。我现在正在考虑使用JLayeredPane来叠加按钮,但我认为会出现问题,因为如果另一个按钮覆盖在上面,则某些部分的按钮将无法点击。
是否可能实现我想要的此形状的功能(5个按钮)?

1
你能否找到大小写锁定键并在句子开头和"I"这个单词中一贯地使用它?我尝试阅读那个字母的混乱但总是迷失方向。此外,“..surimposed buttons..”不管是更仔细地打字还是使用拼写检查器吧。 - Andrew Thompson
顺便说一句 - 那张图片只有一个按钮,但您一直在提到“按钮”(复数-很多)。你说的是单个按钮还是多个按钮? - Andrew Thompson
顺便说一下,非常感谢这个超棒的教程:)) - COD3BOY
我想实现一个有5个按钮的组件,这些按钮看起来像教程中的按钮。这五个按钮是中间的那个加上另外四个,它们来自我将外环分成四部分的部分。 - xtrem06
@AndrewThompson 你觉得制作一个圆形按钮,并在其paint方法中绘制这个图像如何?这样可能会看起来像OP想要的。 - Harry Joy
1个回答

1

我知道这个问题早就被问过了,但是我会创建一个JComponent,将其呈现为该按钮,然后检查点击了图像的哪个部分。就像这样:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.SwingConstants;

public class FivePartCircleButton extends JComponent implements SwingConstants
{
    private static final float PERCENT_PADDING_MIDDLE = 0.1571428571428571f;
    private static final float PERCENT_PADDING_EDGE = 0.0535714285714286f;
    private static Image button;

    private List<ActionListener> topListeners = new LinkedList<ActionListener>();
    private List<ActionListener> rightListeners = new LinkedList<ActionListener>();
    private List<ActionListener> bottomListeners = new LinkedList<ActionListener>();
    private List<ActionListener> leftListeners = new LinkedList<ActionListener>();
    private List<ActionListener> middleListeners = new LinkedList<ActionListener>();
    private String actionCommand;

    public FivePartCircleButton()
    {
        try
        {
            if (button == null)
                button = Toolkit.getDefaultToolkit().createImage(new URL("http://mygimptutorial.com/preview/round-web20-button-with-metal-ring.jpg"));
        }
        catch (MalformedURLException e)    {e.printStackTrace();}

        this.setPreferredSize(new Dimension(280, 280));
        this.addMouseListener(mouseAdapter);
    }

    private MouseAdapter mouseAdapter = new MouseAdapter()
    {
        @Override
        public void mouseClicked(MouseEvent e)
        {
            Ellipse2D innerCircle = getShapeOfOval(PERCENT_PADDING_MIDDLE);
            Ellipse2D outerCircle = getShapeOfOval(PERCENT_PADDING_EDGE);

            if (innerCircle.contains(e.getPoint())) //clicked in the inner circle
                processClick(middleListeners);
            else if (outerCircle.contains(e.getPoint())) //clicked in the outer ring
            {            
                float lineFromTopLeftToBottomRight = e.getY() * ((float)getWidth() / (float)getHeight()); //if we split this button diagonally (top left to bottom right), then this is the x position of that line at this y point
                float lineFromTopRightToBottomLeft = getWidth() - lineFromTopLeftToBottomRight; // the same line as tlBrDividerX but mirrored

                if (e.getX() < lineFromTopLeftToBottomRight) //clicked on the bottom left half of the ring
                {
                    if (e.getX() < lineFromTopRightToBottomLeft) //clicked on the left quadrant of the ring
                        processClick(leftListeners);
                    else //clicked on the bottom quadrant of the ring
                        processClick(bottomListeners); 
                }
                else //clicked on the top right half of the ring
                {
                    if (e.getX() < lineFromTopRightToBottomLeft) //clicked on the top quadrant of the ring
                        processClick(topListeners);
                    else //clicked on the right quadrant of the ring
                        processClick(rightListeners);
                }
            }
        }
    };

    /**
     * Informs all of the listeners that an action has been performed
     * @param listeners - which set of listeners to inform
     */
    private void processClick(List<ActionListener> listeners)
    {
        for (ActionListener l : listeners)
            l.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand));
    }

    /**
     * @param listener - the listener to add
     * @param side - one of SwingConstants.TOP, SwingConstants.RIGHT, SwingConstants.BOTTOM, SwingConstants.LEFT, SwingConstants.CENTER,  
     */
    public void addActionListener(ActionListener listener, int side)
    {
        switch (side)
        {
        case TOP:
            topListeners.add(listener);
            break;
        case RIGHT:
            rightListeners.add(listener);
            break;
        case BOTTOM:
            bottomListeners.add(listener);
            break;
        case LEFT:
            leftListeners.add(listener);
            break;
        case CENTER:
            middleListeners.add(listener);
            break;
        }
    }

    /**
     * Creates an oval based on the size of this component with the given padding percentage
     * @param percentPadding
     * @return an oval with the given padding
     */
    private Ellipse2D getShapeOfOval(float percentPadding)
    {
        float x = getWidth() * percentPadding;
        float y = getHeight() * percentPadding;
        float w = getWidth() - x - x;
        float h = getHeight() - y - y;

        Ellipse2D circle = new Ellipse2D.Float(x, y, w, h);
        return circle;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        g.drawImage(button, 0, 0, this.getWidth(), this.getHeight(), this);
    }

    /**
     * Sets the action command for this button.
     * @param actionCommand - the action command for this button
     */
    public void setActionCommand(String actionCommand)
    {
        this.actionCommand = actionCommand;
    }
}

简而言之,按钮会呈现为您链接的图像。然后,当您单击图像时,它会检查您单击了图像的哪个部分。这是通过创建两个与您图像上的椭圆匹配的椭圆来完成的。如果您单击的点在较小的椭圆内,则通知中间的ActionListeners。如果不在其中,但在较大的椭圆内,则我们知道单击在环上。然后,我们检查单击的椭圆的哪一侧,并通知相应的操作侦听器。
另外,请注意:PERCENT_PADDING_MIDDLEPERCENT_PADDING_EDGE是特定于您链接的图像的,并假定图像周围有相等的填充。这是通过将图像上的填充像素数除以图像宽度来确定的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接