Сложное расположение кнопок - PullRequest
3 голосов
/ 20 января 2012

Я хотел бы реализовать кнопку, которая выглядит следующим образом: кнопка :

Round button w/metallic border

Но с внешним кольцом разделить на четыре части, чтобы у меня былочетыре изображения, чтобы сделать кнопки этого плюс среднее изображение для средней кнопки.Для разделения четырех кнопок представьте, что есть крестик или X. Как я могу расположить кнопки, чтобы получить такой компонент, как этот?

Я пробовал с BorderLayout и GridBagLayout, но пробелы из-заПрямоугольная форма поворотных кнопок занимает слишком много места между изображениями каждой кнопки, поэтому она не выглядит хорошо.Сейчас я думаю о JLayeredPane для наложения кнопок, но я думаю, что возникнет проблема, поскольку некоторые части кнопок не будут активными, если над ними находятся другие кнопки.

Возможно ли реализовать компонентэту форму с функциональностью (5 кнопок) я хочу?

1 Ответ

1 голос
/ 01 марта 2012

Я понимаю, что этот вопрос задавался довольно давно, но я бы создал 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_MIDDLE и PERCENT_PADDING_EDGE относятся к изображению, с которым вы связаны, и допускают одинаковое заполнение вокруг изображения. Это было определено путем взятия количества дополнительных пикселей на изображении и деления его на ширину изображения.

...