有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

swing如何在java中使用getWidth()和getHeight()将星形形状居中

我无法将星星形状居中。问题是我硬编码了每个坐标的点。问题是我没有得到正确的位置,尽管我创造了一个完美的五星。更多的问题是,如果我想通过单击按钮来重新缩放形状,使其变大或变小,该怎么办? 这是我的密码

public void run() {
            DifferentShapes panel = new DifferentShapes();
            JFrame frame = new JFrame("Different Shapes");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400,400);
            frame.setVisible(true);  
            frame.add(panel);
            frame.setJMenuBar(panel.getMenuBAr());
        }

    public void star(Graphics shape) {
    //        int sizeReq = 1;
    int [] starX =  new int[] {250, 262, 304, 268, 278, 250, 222, 232, 196, 238};
    int []starY =  new int[] {200, 236, 236, 254, 296, 272, 296, 254, 236, 236};
    shape.fillPolygon(starX, starY, starX.length);    

}

共 (2) 个答案

  1. # 1 楼答案

    你可能想考虑使用Shape Utils助手类来为你生成星,这样你就不需要手动计算恒星上的所有点。

    基本上,使用该类只需要两行代码:

    star = ShapeUtils.radiusShape(10, 55, 22);
    

    这将生成一个从中心到55到22像素的10个点交替的恒星

    生成的第一个点将位于水平线上。由于有5个大点,这意味着它们将每72度生成一次。由于希望顶点位于垂直轴上,因此需要将所有点旋转-18度:

    star = ShapeUtils.rotate(star, -18);
    

    下面是一个简单的示例,展示了如何在面板中绘制居中的星星:

    import java.awt.*;
    import javax.swing.*;
    
    public class ShapeSSCCE extends JPanel
    {
        private Shape star;
    
        public ShapeSSCCE()
        {
            star = ShapeUtils.radiusShape(10, 55, 22);
            star = ShapeUtils.rotate(star, -18);
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            Rectangle bounds = star.getBounds();
    
            return new Dimension(bounds.width, bounds.height);
        }
    
        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle bounds = star.getBounds();
            int x = (getWidth()  - bounds.width)  / 2;
            int y = (getHeight() - bounds.height) / 2;
            g2d.translate(x, y);
            g2d.fill( star );
            g2d.dispose();
        }
    
        private static void createAndShowUI()
        {
            JFrame frame = new JFrame("ShapeSSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add( new ShapeSSCCE() );
            frame.setSize(200, 200);
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowUI();
                }
            });
        }
    }
    

    尝试使用带/不带旋转形状的代码查看差异

    如果不想进行自定义绘制,那么可以使用上面链接中的ShapeIcon类。然后,您可以将星星视为图标,并将其添加到标签中:

    Shape star = ShapeUtils.radiusShape(10, 55, 22);
    star = ShapeUtils.rotate(star, -18);
    ShapeIcon starIcon = new ShapeIcon(star, Color.RED);
    JLabel starLabel = new JLabel( starIcon );
    

    I want to rescale the shape to make it bigger or small by clicking a button?

    你可以:

    1. 使用带有新值的ShapeUtils类创建一个新形状
    2. 使用仿射变换缩放现有形状。看看ShapeUtils。旋转(…)方法来查看如何对旋转执行此操作。其逻辑与缩放相似
    3. 使用仿射变换绘制形状时,动态缩放形状。阅读Graphics2D类了解有关设置转换的信息
  2. # 2 楼答案

    没有Shapes API

    您可能会花费大量时间手动转换多边形数组,但更好的解决方案可能是将多边形转换为0x0,以便左上角位于0x0

    基本上,我计算了每个数组的最小/最大值,然后从所有值中减去“最小”值

    protected static int[] minMax(int[] values) {
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int value : values) {
            min = Math.min(min, value);
            max = Math.max(max, value);
        }
    
        return new int[]{min, max};
    }
    
    protected static int[] normalise(int[] values, int min) {
        for (int index = 0; index < values.length; index++) {
            values[index] = values[index] - min;
        }
        return values;
    }
    

    所以从

    [250, 262, 304, 268, 278, 250, 222, 232, 196, 238]
    [200, 236, 236, 254, 296, 272, 296, 254, 236, 236]
    

    翻译成

    [54, 66, 108, 72, 82, 54, 26, 36, 0, 42]
    [0, 36, 36, 54, 96, 72, 96, 54, 36, 36]
    

    当画出来的时候,看起来像

    Top/Left

    你可能在想,这不太好,我希望它在中心,但要进入中心,我们需要多边形的宽度和高度

    为了实现这一点,我将转换后的数组传递给minMax方法,并使用返回值的第二个元素,它给了我一个108x96widthxheight)的值,现在我们有了将形状居中所需的信息

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics copy = g.create();
        int x = (getWidth() - maxWidth) / 2;
        int y = (getHeight() - maxHeight) / 2;
        copy.translate(x, y);
        copy.fillPolygon(starX, starY, starX.length);
        copy.dispose();
    }
    

    基本上,所有这些都是使用maxWidthmaxHeight值来计算当前组件中的中心位置,将Graphics上下文转换为适当的偏移量,并绘制多边形。平移会移动原点位置(即0x0上下文的Graphics点),从而允许用户更改多边形的绘制位置

    Star in the middle

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.util.Arrays;
    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();
        }
    
        protected static int[] minMax(int[] values) {
            int min = Integer.MAX_VALUE;
            int max = Integer.MIN_VALUE;
            for (int value : values) {
                min = Math.min(min, value);
                max = Math.max(max, value);
            }
    
            return new int[]{min, max};
        }
    
        protected static int[] normalise(int[] values, int min) {
            for (int index = 0; index < values.length; index++) {
                values[index] = values[index] - min;
            }
            return values;
        }
    
        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 {
    
            private int starX[];
            private int starY[];
    
            private int maxWidth, maxHeight;
    
            public TestPane() {
                starX = new int[]{250, 262, 304, 268, 278, 250, 222, 232, 196, 238};
                starY = new int[]{200, 236, 236, 254, 296, 272, 296, 254, 236, 236};
    
                int[] minMaxX = minMax(starX);
                int[] minMaxY = minMax(starY);
    
                starX = normalise(starX, minMaxX[0]);
                starY = normalise(starY, minMaxY[0]);
    
                minMaxX = minMax(starX);
                minMaxY = minMax(starY);
    
                maxWidth = minMaxX[1];
                maxHeight = minMaxY[1];
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics copy = g.create();
                int x = (getWidth() - maxWidth) / 2;
                int y = (getHeight() - maxHeight) / 2;
                copy.translate(x, y);
                copy.fillPolygon(starX, starY, starX.length);
                copy.dispose();
            }
    
        }
    
    }
    

    所以,关于你所知道的,你应该看到为你的形状使用0x0原点的重要性

    查看2D GraphicsTransforming Shapes, Text, and Images了解更多详细信息

    缩放

    可通过Graphics2D#scale进行缩放

    Scale

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D copy = (Graphics2D) g.create();
        double scale = slider.getValue() / 100d;
        int x = (getWidth() - maxWidth) / 2;
        int y = (getHeight() - maxHeight) / 2;
        copy.translate(x, y);
        copy.scale(scale, scale);
        copy.fillPolygon(starX, starY, starX.length);
        copy.dispose();
    }
    

    但这会缩放像素,这可能不会给出你想要的结果

    在有人跳下我的喉咙之前,如果你想让它再次居中,你需要缩放maxWidthmaxHeight

    使用Shapes API

    正如我在过去说过的,使用2D shapes API会获得更好的结果,它们是自包含的,很容易移动,当它们被缩放时,会得到更好的结果

    例如,使用上面的“翻译”值,您应该创建一个很好的自定义、可重用的类

    public class StarShape extends Path2D.Double {
    
        public StarShape() {
            moveTo(54, 0);
            lineTo(66, 36);
            lineTo(108, 36);
            lineTo(75, 54);
            lineTo(82, 96);
            lineTo(54, 72);
            lineTo(26, 96);
            lineTo(36, 54);
            lineTo(0, 36);
            lineTo(42, 36);
            closePath();
        }
    
    }
    

    知道吗,我不知道你的情况,但这很容易阅读,而且你可以很容易地在一些图表纸上画出来

    现在,通过做一些简单的事情就可以很容易地解决这个问题,比如

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.fill(new StarShape());
        g2d.dispose();
    }
    

    但是,等等,我们希望它以中心为中心,一切都变得简单

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        Rectangle bounds = starShape.getBounds();
        int x = (getWidth() - bounds.width) / 2;
        int y = (getHeight() - bounds.height) / 2;
        g2d.fill(starShape.createTransformedShape(AffineTransform.getTranslateInstance(x, y)));
        g2d.dispose();
    }
    

    这比非形状API方法的代码要少得多

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.geom.AffineTransform;
    import java.awt.geom.Path2D;
    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 StarShape extends Path2D.Double {
    
            public StarShape() {
                moveTo(54, 0);
                lineTo(66, 36);
                lineTo(108, 36);
                lineTo(75, 54);
                lineTo(82, 96);
                lineTo(54, 72);
                lineTo(26, 96);
                lineTo(36, 54);
                lineTo(0, 36);
                lineTo(42, 36);
                closePath();
            }
    
        }
    
        public class TestPane extends JPanel {
    
            private StarShape starShape;
    
            public TestPane() {
                starShape = new StarShape();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                Rectangle bounds = starShape.getBounds();
                int x = (getWidth() - bounds.width) / 2;
                int y = (getHeight() - bounds.height) / 2;
                g2d.fill(starShape.createTransformedShape(AffineTransform.getTranslateInstance(x, y)));
                g2d.dispose();
            }
    
        }
    
    }
    

    缩放

    一般来说,缩放使用与转换相同的过程,但是,您得到的好处是,您可以缩放Shape,然后单独进行转换,允许您独立地获得缩放ShapeRectangle边界。它还可以缩放矢量(点),而不是像素,这将给你一个更好的结果

    Scales

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        double scale = slider.getValue() / 100d;
        Shape shape = starShape.createTransformedShape(AffineTransform.getScaleInstance(scale, scale));
        Rectangle bounds = shape.getBounds();
        int x = (getWidth() - bounds.width) / 2;
        int y = (getHeight() - bounds.height) / 2;
        GeneralPath path = new GeneralPath();
        path.append(shape.getPathIterator(AffineTransform.getTranslateInstance(x, y)), true);
        g2d.fill(path);
        g2d.dispose();
    }
    

    所以,简短的答案是,使用Shapes API,长的答案是,使用Shapes API,你不需要为你面临的每个问题重新设计轮子