我有问题以星形为中心。问题是我硬编码了每个坐标的点。而这个问题在于我没有找到合适的位置,尽管我创造了一个完美的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);
}
答案 0 :(得分:4)
您可能会花费大量时间手动翻译多边形数组,但更好的解决方案可能是将多边形转换为0x0
,以便左/右上角位于0x0
基本上,我计算了每个数组的最小值/最大值,然后从所有值中减去“min”值......
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]
在绘制时,看起来像......
你现在可能正在考虑,好吧,这不太好,我想把它放在中心,但要进入中心,我们需要多边形的宽度和高度
为了达到这个目的,我获取了已翻译的数组,并通过minMax
方法传递了它们,并使用了返回值的第二个元素,它给了我108x96
的值width
x height
),现在我们拥有了塑造中心所需的信息
@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();
}
基本上,所有这一切都使用maxWidth
和maxHeight
值来计算当前组件中的中心位置,将Graphics
上下文转换为适当的偏移并绘制多边形。平移移动原点位置(0x0
上下文的Graphics
点),允许用于更改多边形的绘制位置。
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 Graphics和Transforming Shapes, Text, and Images
缩放可以通过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();
}
但是这会缩放可能无法提供所需结果的像素。
在有人跳下我的喉咙之前,如果你想让它再次居中,你还需要缩放maxWidth
和maxHeight
值
正如我在过去所说,使用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
然后单独翻译它的好处,让你获得Rectangle
界限缩放Shape
独立的。它还可以缩放矢量(点)而不是像素,这样可以获得更好的效果......
@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,你不需要为你遇到的每个问题重新发明轮子
答案 1 :(得分:2)
您可能需要考虑使用Shape Utils辅助类为您生成星星,这样您就不需要手动计算星上的所有点。
基本上你只需要两行代码来使用该类:
star = ShapeUtils.radiusShape(10, 55, 22);
这将产生一个10点,从中心55到22像素交替出现。
生成的第一个点将在水平线上。由于有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
类。然后你可以将星星视为一个Icon并将其添加到标签:
Shape star = ShapeUtils.radiusShape(10, 55, 22);
star = ShapeUtils.rotate(star, -18);
ShapeIcon starIcon = new ShapeIcon(star, Color.RED);
JLabel starLabel = new JLabel( starIcon );
我想通过点击按钮重新缩放形状以使其变大或变小?
你可以:
ShapeUtils
类创建新形状