java中如何使用getWidth()和getHeight()使星形居中 [英] How to use getWidth() and getHeight() to center the star shape in java

查看:94
本文介绍了java中如何使用getWidth()和getHeight()使星形居中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

public void run() {DifferentShapes 面板 = new DifferentShapes();JFrame frame = new JFrame("不同形状");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(400,400);frame.setVisible(true);框架.添加(面板);frame.setJMenuBar(panel.getMenuBAr());}public void star(图形形状){//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;对于(整数值:值){min = Math.min(min, value);max = Math.max(max, value);}返回新的 int[]{min, max};}protected static int[] normalise(int[] values, int min) {for (int index = 0; index < values.length; index++) {值[索引] = 值[索引] - 分钟;}返回值;}

所以从...开始

[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]

涂漆时看起来像……

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

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

@Override受保护的无效paintComponent(图形g){super.paintComponent(g);图形复制 = g.create();int x = (getWidth() - maxWidth)/2;int y = (getHeight() - maxHeight)/2;copy.translate(x, y);copy.fillPolygon(starX, starY, starX.length);复制处理();}

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

import java.awt.Dimension;导入 java.awt.EventQueue;导入 java.awt.Graphics;导入 java.awt.Graphics2D;导入 java.util.Arrays;导入 javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.UIManager;导入 javax.swing.UnsupportedLookAndFeelException;公共类测试{公共静态无效主(字符串 [] args){新测试();}protected static int[] minMax(int[] values) {int min = Integer.MAX_VALUE;int max = Integer.MIN_VALUE;对于(整数值:值){min = Math.min(min, value);max = Math.max(max, value);}返回新的 int[]{min, max};}protected static int[] normalise(int[] values, int min) {for (int index = 0; index < values.length; index++) {值[索引] = 值[索引] - 分钟;}返回值;}公共测试(){EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){尝试 {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {ex.printStackTrace();}JFrame frame = new JFrame("测试");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(new TestPane());框架.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共类 TestPane 扩展 JPanel {私人 int starX[];私人 int starY[];私人 int maxWidth, maxHeight;公共测试窗格(){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];}@覆盖公共维度 getPreferredSize() {返回新维度(200, 200);}@覆盖受保护的无效paintComponent(图形g){super.paintComponent(g);图形复制 = g.create();int x = (getWidth() - maxWidth)/2;int y = (getHeight() - maxHeight)/2;copy.translate(x, y);copy.fillPolygon(starX, starY, starX.length);复制处理();}}}

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

查看

@Override受保护的无效paintComponent(图形g){super.paintComponent(g);Graphics2D copy = (Graphics2D) g.create();双刻度 = 滑块.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);复制处理();}

但这会缩放像素,可能无法提供您想要的结果.

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

使用 Shapes API

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

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

public class StarShape extends Path2D.Double {公共星形(){移动到(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);关闭路径();}}

知道,我不了解你,但它更容易阅读,你可以轻松地将其绘制在一些方格纸上.

现在只需做一些简单的事情就可以轻松填满......

@Override受保护的无效paintComponent(图形g){super.paintComponent(g);Graphics2D g2d = (Graphics2D) g.create();g2d.fill(new StarShape());g2d.dispose();}

但是,等等,我们希望它居中,一切都很简单......

@Override受保护的无效paintComponent(图形g){super.paintComponent(g);Graphics2D g2d = (Graphics2D) g.create();矩形边界 = 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;导入 java.awt.EventQueue;导入 java.awt.Graphics;导入 java.awt.Graphics2D;导入 java.awt.Rectangle;导入 java.awt.geom.AffineTransform;导入 java.awt.geom.Path2D;导入 javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.UIManager;导入 javax.swing.UnsupportedLookAndFeelException;公共类测试{公共静态无效主(字符串 [] args){新测试();}公共测试(){EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){尝试 {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {ex.printStackTrace();}JFrame frame = new JFrame("测试");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(new TestPane());框架.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共类 StarShape 扩展 Path2D.Double {公共星形(){移动到(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);关闭路径();}}公共类 TestPane 扩展 JPanel {私人星形星形;公共测试窗格(){starShape = new StarShape();}@覆盖公共维度 getPreferredSize() {返回新维度(200, 200);}@覆盖受保护的无效paintComponent(图形g){super.paintComponent(g);Graphics2D g2d = (Graphics2D) g.create();矩形边界 = 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 的矩形 边界.它还缩放矢量(点)而不是像素,这会给你一个更好的结果......

@Override受保护的无效paintComponent(图形g){super.paintComponent(g);Graphics2D g2d = (Graphics2D) g.create();双刻度 = 滑块.getValue()/100d;Shape shape = starShape.createTransformedShape(AffineTransform.getScaleInstance(scale, scale));矩形边界 = 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(路径);g2d.dispose();}

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

I'm having problem centering the star shape. The problem is that I hard coded the points for each coordinate. And the problem with this is that Im not getting the right position although I created a perfect 5 star. On more problem is that what if I want to rescale the shape to make it bigger or small by clicking a button? Here's my code.

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

}

解决方案

Without the Shapes API

You could spend a lot of time manually translating the polygon array, but a better solution might be to translate the polygon to 0x0, so that the top/left corner will be at 0x0

Basically, I calculated the min/max values for each array and then subtracted the "min" value from all the values...

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

So starting with...

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

translated to...

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

which when painted, looks something like...

You're probably thinking about now, well, that's not much good, I want it in the centre, but to get in the center, we need the width and height of the polygon

To achieve this, I took the translated arrays and passed them through the minMax method and used the second element of the return value, which gave me a value of 108x96 (widthxheight), now we have the information we need to center the shape

@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();
}

Basically, all this does is uses the maxWidth and maxHeight values to calculate the center location within the current component, translate the Graphics context to the appropriate offset and paints the polygon. The translation moves the origin position (the 0x0 point of the Graphics context) which allows use to change where the polygon will be painted.

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

    }

}

So, about know, you should see the importance of using a 0x0 origin for your shapes.

Have a look at 2D Graphics and Transforming Shapes, Text, and Images for more details

Scaling...

Scaling can be done through Graphics2D#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();
}

but this scales the pixels which might not give the results you want.

Before someone jumps down my throat, if you want to get it centered again, you'll need to scale the maxWidth and maxHeight values as well

With the Shapes API

As I've said in the past, you will get better results with the 2D shapes API, they are self contained, they are easily moved and you will get a better results when they are scaled

For example, using the "translated" values from above, you should create a nice custom, re-usable, class...

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

}

Know, I don't know about you, but that is so much easier to read and you could easily plot this on some graph paper.

Now it's easily filled by doing something as simple as...

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

But, wait, we want it centered, all to easy...

@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();
}

Well, that was a lot less code than the non-shapes API approach...

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

    }

}

Scaling

Generally speaking, scaling uses the same process as translating, BUT, what you get, is the benefit that you can scale a Shape and then translate it separately, allowing you to get the Rectangle bounds of the scaled Shape independently. It also scales the vector (points) and not pixels which will give you a better result...

@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();
}

So, the short answer is, use the Shapes API, the long answer is, use the Shapes API, you won't need to reinvent the wheel for each problem you face

这篇关于java中如何使用getWidth()和getHeight()使星形居中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆