【问题标题】:GUI button placementGUI 按钮位置
【发布时间】:2015-08-11 09:30:27
【问题描述】:

我正在尝试设计一个带有三角形按钮的 GUI。我已经正确地创建了三角形按钮类,因为使用我的类构造函数创建了一个 JButton 会在页面上产生一个三角形按钮,但是在按钮的放置方面我做得不够。

谁能指导我或有一个用三角形按钮创建六边形的例子?

这是我的 TriangleButton 类供参考:

import java.awt.Polygon;
import java.awt.Shape;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

class TriangleButton extends JButton {
    final static double side_len = 52; //Change for variable triangle size
    final static double y_offset = (Math.sqrt(3) * side_len / 2);
    private Shape triangle;

    public TriangleButton(int spot){
        triangle = createTriangle(spot);
    }

    public void paintBorder( Graphics g ) {
        ((Graphics2D)g).draw(triangle);
    }
    public void paintComponent( Graphics g ) {
        ((Graphics2D)g).fill(triangle);
    }
    public Dimension getPreferredSize() {
        return new Dimension((int)side_len, (int)y_offset);
    }
    public boolean contains(int x, int y) {
        return triangle.contains(x, y);
    }

    private Shape createTriangle(int spot) {
        Polygon p = new Polygon();
        p.addPoint( 0   , 0 );
        p.addPoint( (int)side_len , 0   );
        p.addPoint( (int)side_len/2, (int)(y_offset)  );
        return p;
    }
}

我心目中的样子应该是……

按钮之间的空间..基本上只是向上和向下的三角形排列。 但是任何能让我朝着正确方向前进的东西都将不胜感激!

【问题讨论】:

  • 我可能是错的,但我不能 100% 确定这可以通过使用或扩展 JButton 来实现。您可能需要创建自己的 Button 类,该类使用或扩展 JComponent 或 JPanel,您可以在上面进行绘制,并使用 MouseListener 更改 mousePressed 和 mouseReleased 上的图像。我希望我是错的,所以在你开始扔代码之前让我们看看其他人要说什么。
  • 我也希望不要,哈哈。我认为由于按钮只是简单地排成一排,这不会很困难吗?但在这里我问我知道什么..
  • 你用这些按钮做什么?
  • 通过制作一个围绕(你猜对了!)与之交互的三角形按钮的小游戏自学 GUI 知识。最后,我希望能够创建可变大小的按钮区域。现在正在寻找创建实际上不会显示(并且不会与之交互)的“空白”按钮来填充更大的 GridLayout 中的点。

标签: java swing user-interface jframe jbutton


【解决方案1】:

作为替代方案,由于生成合适的布局以允许组件重叠的复杂性,您可以简单地创建一个按钮来容纳所有三角形并提供集中控制,例如

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Path2D;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.DefaultButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
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();
                }

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

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            HexagonButton btn = new HexagonButton();
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.out.println(Arrays.toString(btn.getSelectedObjects()));
                    System.out.println(e.getActionCommand());
                }
            });
            add(btn);
        }

    }

    public class HexagonButton extends AbstractButton {

        public static final String TOP_RIGHT_QUAD = "Top.right";
        public static final String TOP_QUAD = "Top";
        public static final String TOP_LEFT_QUAD = "Top.left";
        public static final String BOTTOM_LEFT_QUAD = "Bottom.left";
        public static final String BOTTOM_QUAD = "Bottom";
        public static final String BOTTOM_RIGHT_QUAD = "Bottom.right";

        private Shape top;
        private Shape topRight;
        private Shape topLeft;
        private Shape bottomLeft;
        private Shape bottomRight;
        private Shape bottom;

        private Map<String, Shape> paths;
        private String selectedQuad;

        public HexagonButton() {
            setModel(new DefaultButtonModel());
            createPaths();

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {

                    String previousQuad = selectedQuad;
                    selectedQuad = null;
                    for (String quad : paths.keySet()) {

                        Shape shape = paths.get(quad);
                        if (shape.contains(e.getPoint())) {
                            getModel().setPressed(true);
                            getModel().setArmed(true);
                            selectedQuad = quad;
                            if (!selectedQuad.equals(previousQuad)) {
                                fireActionPerformed(new ActionEvent(HexagonButton.this, ActionEvent.ACTION_PERFORMED, selectedQuad));
                            }
                            break;
                        }

                    }
                    repaint();

                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    getModel().setArmed(false);
                    getModel().setPressed(false);
                }
            });

        }

        @Override
        public Object[] getSelectedObjects() {
            return new Object[]{selectedQuad};
        }

        @Override
        public void invalidate() {
            super.invalidate();
            createPaths();
        }

        protected void createPaths() {
            topRight = create(0d, -60d);
            top = create(-60d, -120d);
            topLeft = create(-120d, -180d);
            bottomLeft = create(-180d, -240d);
            bottom = create(-240d, -300d);
            bottomRight = create(-300d, -360d);

            paths = new HashMap<>(6);
            paths.put(TOP_RIGHT_QUAD, topRight);
            paths.put(TOP_QUAD, top);
            paths.put(TOP_LEFT_QUAD, topLeft);
            paths.put(BOTTOM_LEFT_QUAD, bottomLeft);
            paths.put(BOTTOM_QUAD, bottom);
            paths.put(BOTTOM_RIGHT_QUAD, bottomRight);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(104, 104);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
            Graphics2D g2d = (Graphics2D) g.create();
            if (selectedQuad != null) {
                Shape path = paths.get(selectedQuad);
                g2d.setColor(UIManager.getColor("List.selectionBackground"));
                g2d.fill(path);
            }
            g2d.setColor(getForeground());
            g2d.draw(topRight);
            g2d.draw(top);
            g2d.draw(topLeft);
            g2d.draw(bottomLeft);
            g2d.draw(bottom);
            g2d.draw(bottomRight);
            g2d.dispose();
        }

        public Shape create(double startAngle, double endAngle) {

            double width = getWidth();
            double height = getHeight();

            double radius = Math.min(width, height) / 2;

            double xOffset = width - radius;
            double yOffset = height - radius;

            double startX = xOffset + radius * (Math.cos(Math.toRadians(startAngle)));
            double startY = yOffset + radius * (Math.sin(Math.toRadians(startAngle)));

            double endX = xOffset + radius * (Math.cos(Math.toRadians(endAngle)));
            double endY = yOffset + radius * (Math.sin(Math.toRadians(endAngle)));

            Path2D path = new Path2D.Double();
            path.moveTo(xOffset, yOffset);
            path.lineTo(startX, startY);
            path.lineTo(endX, endY);
            path.closePath();

            return path;

        }

    }

    public static class TriangleButton extends JButton {

        final static double side_len = 52; //Change for variable triangle size
        final static double y_offset = (Math.sqrt(3) * side_len / 2);
        private Shape triangle;

        public TriangleButton(int spot) {
            triangle = createTriangle(spot);
        }

        @Override
        public void paintBorder(Graphics g) {
            super.paintBorder(g);
            ((Graphics2D) g).draw(triangle);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            ((Graphics2D) g).fill(triangle);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension((int) side_len, (int) y_offset);
        }

        @Override
        public boolean contains(int x, int y) {
            return triangle.contains(x, y);
        }

        private Shape createTriangle(int spot) {
            Polygon p = new Polygon();
            p.addPoint(0, 0);
            p.addPoint((int) side_len, 0);
            p.addPoint((int) side_len / 2, (int) (y_offset));
            return p;
        }
    }
}

【讨论】:

  • 这是一项了不起的工作,感谢您和其他所有人。
  • 作为后续,是否可以让两个六边形按钮彼此相邻以使两侧相互接触?简单地在另一个按钮上使用 add() 显然会使它们彼此相邻但通过点连接。我只需要知道如何在 JPanel 中移动组件(还没有找到任何东西)
  • 是的,尝试布局单个三角形会更简单。 FlowLayout 可以做的很简单,但是 GridBagLayout 会给你更灵活的
【解决方案2】:

使用您的课程,我做了一些更改并提出了以下建议:

import java.awt.*;
import java.awt.Shape;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class TriangleButton2 extends JButton {
    final static double side_len = 52; //Change for variable triangle size
    final static double y_offset = (Math.sqrt(3) * side_len / 2);
    private Shape triangle;

    public TriangleButton2(int degrees){
        triangle = createTriangle(degrees);
        setRolloverEnabled( false );
        setContentAreaFilled( false );
        setBorderPainted( false );
    }

    public void paintBorder( Graphics g ) {
        ((Graphics2D)g).draw(triangle);
    }
    public void paintComponent( Graphics g ) {
        super.paintComponent(g);
        ((Graphics2D)g).fill(triangle);
    }
    public Dimension getPreferredSize() {
        return new Dimension((int)side_len, (int)y_offset);
    }
    public boolean contains(int x, int y) {
        return triangle.contains(x, y);
    }

    private Shape createTriangle(int degrees) {
        Polygon p = new Polygon();
        p.addPoint( 0   , 0 );
        p.addPoint( (int)side_len , 0   );
        p.addPoint( (int)side_len/2, (int)(y_offset)  );

        return ShapeUtils.rotate(p, degrees);

//        return p;
    }

    private static void createAndShowGUI()
    {
        JPanel panelNorth = new JPanel( new FlowLayout(FlowLayout.CENTER, -22, 2) );
        panelNorth.add( new TriangleButton2(180) );
        panelNorth.add( new TriangleButton2(0) );
        panelNorth.add( new TriangleButton2(180) );

        JPanel panelSouth = new JPanel( new FlowLayout(FlowLayout.CENTER, -22, 1) );
        panelSouth.add( new TriangleButton2(0) );
        panelSouth.add( new TriangleButton2(180) );
        panelSouth.add( new TriangleButton2(0) );

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panelNorth, BorderLayout.NORTH);
        frame.add(panelSouth, BorderLayout.SOUTH);
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

上面的代码使用了Playing With Shapes中的ShapeUtils类。

不确定您希望按钮提供的确切功能。当您单击按钮或将鼠标悬停在按钮上时,您当前的植入没有任何视觉效果。

在这种情况下,您可能只想考虑创建一个图标来表示您的三角形。您可以使用Playing With Shapes 中的ShapeIcon 类来创建三角形图标。然后,您可以使用 Playing With Shapes 中的 ShapeComponent 类来创建添加到面板的实际组件。

FlowLayout 展示了如何重叠按钮以获得所需的布局效果。

【讨论】:

  • 非常感谢!这对我正在尝试做的事情非常有帮助。
【解决方案3】:

查看此页面以获取一些相关信息: Creating custom JButton from images containing transparent pixels

从三角形图像创建 JButton 可能更容易。

【讨论】:

  • 我会调查的,谢谢。我没有看到任何关于安置的信息,这是我的主要问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-27
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多