java - 如何使用 getWidth() 和 getHeight() 在 java 中使星形居中

标签 java swing

我在将星形居中时遇到问题。问题是我对每个坐标的点进行了硬编码。问题是,尽管我创造了完美的 5 星,但我没有得到正确的位置。更多的问题是,如果我想通过单击按钮来重新调整形状以使其变大或变小怎么办? 这是我的代码。

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);    

}

最佳答案

没有 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 方法,并使用返回值的第二个元素,这给了我一个值 108x96 (宽度x高度),现在我们有了使形状居中所需的信息

@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 上下文到适当的偏移并绘制多边形。平移会移动原点位置(Graphics 上下文的 0x0 点),从而允许更改多边形的绘制位置。

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 形状 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 然后单独翻译它,从而获得 独立缩放的Shape的矩形边界。它还缩放 vector (点)而不是像素,这将为您提供更好的结果......

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,您无需为遇到的每个问题重新发明轮子

关于java - 如何使用 getWidth() 和 getHeight() 在 java 中使星形居中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35074888/

相关文章:

java - 如何使用neo4j-jdbc连接Neo4j 3.0数据库?

java - 绘制隐藏的 Java swing 组件

java - 未检测到 JMenuItem Actionlistener

javascript - Swing html中的Java回调

java - Java 中的 Curl --user 和 -d 等效项

java - 为什么执行AsyncTask时不需要捕获TimeoutException?

java - Log4J 自定义字段

java - android - 使用 VideoView 的多个实例时出错

java - 使用 JComponents 的表单中的监听器

java - Java Swing 中的垂直堆叠布局?