一些关于绘制彩虹的 Java 程序的帮助

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12718827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 09:56:55  来源:igfitidea点击:

Some help on a Java program to draw a rainbow

javaswingdrawbackground-color

提问by user1629075

I'll be candid about this; it is a homework assignment, but can someone guide me in the right direction and explain to me how some parts of the code are supposed to work? The directions are below the code and the questions.

我会坦诚相待;这是一项家庭作业,但有人可以指导我朝着正确的方向前进并向我解释代码的某些部分应该如何工作吗?说明在代码和问题下方。

This is my code so far:

到目前为止,这是我的代码:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Rainbow extends JPanel
{
  // Declare skyColor:
     private final Color skyColor = Color.CYAN;

  public Rainbow()
  {
    setBackground(skyColor);
  } 
  // Draws the rainbow.
  public void paintComponent(Graphics g)
  {
super.paintComponent(g);
int width = getWidth();    
int height = getHeight();

// Declare and initialize local int variables xCenter, yCenter
// that represent the center of the rainbow rings:
int xCenter = width/2;
int yCenter = (height * 3) /4;

// Declare and initialize the radius of the large semicircle:
  int largeRadius = width/4;

g.setColor(Color.RED);

// Draw the large semicircle:
 g.fillArc(xCenter,yCenter,largeRadius,height,0,180);
// Declare and initialize the radii of the small and medium
// semicircles and draw them:
int smallRadius = height/4;
 g.setColor(Color.MAGENTA);

 g.fillArc(xCenter,yCenter,width,height,0,180);
 int mediumRadius = (int) Math.sqrt(smallRadius * largeRadius);
 g.setColor(Color.GREEN);
 g.fillArc(xCenter,yCenter,width,height,0,180);


// Calculate the radius of the innermost (sky-color) semicircle
// so that the width of the middle (green) ring is the
// arithmetic mean of the widths of the red and magenta rings:


// Draw the sky-color semicircle:
 g.fillArc(xCenter,yCenter,width,height,0,180);
  }

  public static void main(String[] args)
  {
JFrame w = new JFrame("Rainbow");
w.setBounds(300, 300, 300, 200);
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = w.getContentPane();
c.add(new Rainbow());
w.setVisible(true);
   }
}

My questions: How exactly does fillArc work; I understand what goes in the parameter, but what must one do so each arc differs from one another? How does one set one color for each arc? I tried doing so, and I ended up with the color listed closest the end showing up and overriding the others. I'll probably have more as a I continue to code.

我的问题:fillArc 究竟是如何工作的?我了解参数中的内容,但是必须做什么才能使每个弧彼此不同?如何为每个弧设置一种颜色?我尝试这样做,最后我列出的颜色最接近末端显示并覆盖其他颜色。随着我继续编码,我可能会有更多。

These were the directions:

这些是方向:

![enter image description here][1]

![在此处输入图像描述][1]

The “rainbow” is made of four overlapping semicircles. The outer ring is red (Color.RED), the middle one is green (Color.GREEN), and the inner ring has the magenta color (Color.MAGENTA). The innermost semicircle has the same color as the background.

“彩虹”由四个重叠的半圆组成。外圈为红色(Color.RED),中间为绿色(Color.GREEN),内圈为洋红色(Color.MAGENTA)。最里面的半圆与背景颜色相同。

Follow the instructions below and fill in the blanks in Rainbow.java.

请按照以下说明填写 Rainbow.java 中的空白。

  1. Start the Rainbow project.

  2. Add a complete comment header with your name before the class declaration at the top of the file.

  3. Add to the Rainbow class a declaration of a private final field skyColor of the type Color, initialized to Color.CYAN (the color of the sky). In Rainbow's constructor, set the window's background to skyColor rather than Color.WHITE.

  4. In the paint method, declare local integer variables xCenter and yCenter that represent the coordinates of the center of the rings. Initialize them to 1/2 width and 3/4 height (down) of the content pane, respectively. (Recall that the origin of graphics coordinates in Java is at the upper left corner of the content pane with the y-axis pointing down.) Do not plug in fixed numbers from the window's dimensions.

  5. Declare a local variable largeRadius that represents the radius of the largest (red) semicircle and initialize it to 1/4 of width.

  6. A method call g.fillArc(x, y, size, size, from, degrees) (with all integer arguments) draws a sector of a circle. x and y are the coordinates of the upper left corner of the rectangle (in this case a square) into which the oval is (logically) inscribed; size is the side of the square (and the diameter of the circle); from is the starting point of the arc in degrees (with 0 at the easternmost point of the horizontal diameter), and degrees (a positive number) is the measure of the arc, going counterclockwise. Add a statement to the paint method to draw the largest (red) semicircle. Test your program.

  7. Add statements to display the medium (green) and small (magenta) semicircles. The radius of the magenta semicircle should be 1/4 of height. The radius of the green one should be the geometric mean (the square root of the product) of the radius of the red semicircle and the radius of the magenta semicircle, rounded to the nearest integer. (A call to Math.sqrt(x) returns the value of square root of x, a double.) Retest your program.

  8. Add statements to display the innermost semicircle of the background (“sky”) color to complete the rainbow. Use the skyColor constant for this semicircle's color. Choose the radius of the sky-color semicircle in such a way that the width of the middle (green) ring is the arithmetic mean of the widths of the red and magenta rings.

  9. Test your program.

  10. Submit your completed program and run output. Your run output (the rainbow picture) can be included by capturing the screen output (Alt-PrintScrn), pasting it into a graphics program (such as MS Paint) and then saving the image to your Eclipse project directory.

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Container;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Rainbow extends JPanel
    {
      //Declare skyColor:
        private final Color skyColor = Color.CYAN;
    
      public Rainbow()
    {
    setBackground(skyColor);
    }
    
     // Draws the rainbow.
    public void paintComponent(Graphics g)
     {
    super.paintComponent(g);
    int width = getWidth();    
    int height = getHeight();
    
    // Declare and initialize local int variables xCenter, yCenter
    // that represent the center of the rainbow rings:
    int xCenter = width/2;
    int yCenter = (height * 3) /4;
    
    // Declare and initialize the radius of the large semicircle:
      int largeRadius = width/4;
    
    g.setColor(Color.RED);
    
    // Draw the large semicircle:
     g.fillArc(xCenter - largeRadius,yCenter - largeRadius   ,largeRadius,largeRadius,0,180);
    // Declare and initialize the radii of the small and medium
    //semicircles and draw them:
     int smallRadius = height/4;
     int mediumRadius = (int) Math.sqrt(smallRadius * largeRadius);
     g.setColor(Color.GREEN);
     g.fillArc(xCenter-(largeRadius+mediumRadius)/2,yCenter-          (largeRadius+mediumRadius)/2,mediumRadius,mediumRadius,0,180);
     g.setColor(Color.MAGENTA);
     g.fillArc(xCenter-(largeRadius+smallRadius)/2,yCenter-(largeRadius+smallRadius)/2,smallRadius,smallRadius,0,180);
    
    
    
    
    // Calculate the radius of the innermost (sky-color) semicircle
    // so that the width of the middle (green) ring is the
    // arithmetic mean of the widths of the red and magenta rings:
       int skyRadius = (int)((2 * Math.sqrt(smallRadius * largeRadius)) - width/4);
    
    // Draw the sky-color semicircle:
     g.setColor(skyColor);
     g.fillArc(xCenter-skyRadius,yCenter-skyRadius,skyRadius,skyRadius,0,180);
    
     }
    
     public static void main(String[] args)
     {
    JFrame w = new JFrame("Rainbow");
    w.setBounds(300, 300, 300, 200);
    w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container c = w.getContentPane();
    c.add(new Rainbow());
    w.setVisible(true);
     }
    }
    
  1. 启动彩虹项目。

  2. 在文件顶部的类声明之前添加带有您姓名的完整注释标题。

  3. 向 Rainbow 类添加 Color 类型的私有最终字段 skyColor 的声明,初始化为 Color.CYAN(天空的颜色)。在 Rainbow 的构造函数中,将窗口的背景设置为 skyColor 而不是 Color.WHITE。

  4. 在paint方法中,声明局部整型变量xCenter和yCenter,代表环的中心坐标。分别将它们初始化为内容窗格的 1/2 宽度和 3/4 高度(向下)。(回想一下,Java 中图形坐标的原点位于内容窗格的左上角,y 轴朝下。)不要插入来自窗口尺寸的固定数字。

  5. 声明一个表示最大(红色)半圆半径的局部变量 largeRadius 并将其初始化为宽度的 1/4。

  6. 方法调用 g.fillArc(x, y, size, size, from, degree)(带有所有整数参数)绘制一个圆的扇区。x 和 y 是矩形(在本例中为正方形)左上角的坐标,椭圆(逻辑上)内接于该矩形;size 是正方形的边长(以及圆的直径);from 是以度为单位的弧的起点(水平直径的最东点为 0),度(正数)是弧的度量,逆时针方向。在paint方法中添加一条语句来绘制最大的(红色)半圆。测试你的程序。

  7. 添加语句以显示中(绿色)和小(品红色)半圆。洋红色半圆的半径应为高度的 1/4。绿色的半径应该是红色半圆半径和洋红色半圆半径的几何平均值(乘积的平方根),四舍五入到最接近的整数。(对 Math.sqrt(x) 的调用返回 x 的平方根值,一个双精度值。)重新测试您的程序。

  8. 添加语句以显示背景(“天空”)颜色的最内半圆以完成彩虹。对这个半圆的颜色使用 skyColor 常量。选择天空色半圆的半径,使中间(绿色)环的宽度是红色和洋红色环宽度的算术平均值。

  9. 测试你的程序。

  10. 提交完成的程序并运行输出。可以通过捕获屏幕输出 (Alt-PrintScrn),将其粘贴到图形程序(例如 MS Paint)中,然后将图像保存到 Eclipse 项目目录来包含您的运行输出(彩虹图片)。

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Container;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Rainbow extends JPanel
    {
      //Declare skyColor:
        private final Color skyColor = Color.CYAN;
    
      public Rainbow()
    {
    setBackground(skyColor);
    }
    
     // Draws the rainbow.
    public void paintComponent(Graphics g)
     {
    super.paintComponent(g);
    int width = getWidth();    
    int height = getHeight();
    
    // Declare and initialize local int variables xCenter, yCenter
    // that represent the center of the rainbow rings:
    int xCenter = width/2;
    int yCenter = (height * 3) /4;
    
    // Declare and initialize the radius of the large semicircle:
      int largeRadius = width/4;
    
    g.setColor(Color.RED);
    
    // Draw the large semicircle:
     g.fillArc(xCenter - largeRadius,yCenter - largeRadius   ,largeRadius,largeRadius,0,180);
    // Declare and initialize the radii of the small and medium
    //semicircles and draw them:
     int smallRadius = height/4;
     int mediumRadius = (int) Math.sqrt(smallRadius * largeRadius);
     g.setColor(Color.GREEN);
     g.fillArc(xCenter-(largeRadius+mediumRadius)/2,yCenter-          (largeRadius+mediumRadius)/2,mediumRadius,mediumRadius,0,180);
     g.setColor(Color.MAGENTA);
     g.fillArc(xCenter-(largeRadius+smallRadius)/2,yCenter-(largeRadius+smallRadius)/2,smallRadius,smallRadius,0,180);
    
    
    
    
    // Calculate the radius of the innermost (sky-color) semicircle
    // so that the width of the middle (green) ring is the
    // arithmetic mean of the widths of the red and magenta rings:
       int skyRadius = (int)((2 * Math.sqrt(smallRadius * largeRadius)) - width/4);
    
    // Draw the sky-color semicircle:
     g.setColor(skyColor);
     g.fillArc(xCenter-skyRadius,yCenter-skyRadius,skyRadius,skyRadius,0,180);
    
     }
    
     public static void main(String[] args)
     {
    JFrame w = new JFrame("Rainbow");
    w.setBounds(300, 300, 300, 200);
    w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container c = w.getContentPane();
    c.add(new Rainbow());
    w.setVisible(true);
     }
    }
    

回答by Clark

fillArc() fills in a section of the circle based upon the parameters you gave it. For example your first arc.

fillArc() 根据您提供的参数填充圆的一部​​分。例如你的第一个弧。

You're drawing the fill arc, which in this case is a semi-circle, of the color red.

您正在绘制红色的填充弧,在本例中为半圆。

//Set the arc color
g.setColor(Color.RED);

// Draw the large semicircle:
g.fillArc(xCenter,yCenter,largeRadius,height,0,180);

circle

圆圈

There's our fillArc. That doesn't look anything like a rainbow. In order to get the rainbow shape, we have to draw a smaller arc inside of it. In your case the next one is green. So we do fillArc again after setting the color to green. But we shrunk the radius a little bit so the green doesn't cover the entire red section.enter image description here

这是我们的fillArc。那看起来不像彩虹。为了得到彩虹的形状,我们必须在它里面画一个更小的弧线。在你的情况下,下一个是绿色的。所以我们在将颜色设置为绿色后再次执行fillArc。但是我们稍微缩小了半径,因此绿色不会覆盖整个红色部分。在此处输入图片说明

Keep in mind when we draw, we're drawing on top, so if you drew the green on first it would be covered by the red one.

请记住,当我们绘制时,我们是在顶部绘制的,因此如果您首先绘制绿色,它将被红色覆盖。

Then we draw another arc inside this once more, but make this one the color of the sky (white in this case). This creates the final rainbow shape. So we do fillArc again, but with a slightly smaller radius and the color white.

然后我们再次在这个里面画另一个弧线,但是把这个弧线设为天空的颜色(在这种情况下是白色的)。这将创建最终的彩虹形状。所以我们再次执行fillArc,但半径稍小,颜色为白色。

rainbow!

彩虹!

And there, we drew a rainbow.

在那里,我们画了一道彩虹。

To center this beautiful creation, we have to understand a few things about the fillArc function.

为了让这个美丽的创作居中,我们必须了解一些关于 fillArc 函数的事情。

The parameters are:

参数是:

public abstract void fillArc(int x,
           int y,
           int width,
           int height,
           int startAngle,
           int arcAngle)

int x and int y represent the coordinates for the upper left hand corner of the arc that you are drawing. The reason your code isn't centering is because of how you're drawing the arc.

int x 和 int y 表示您正在绘制的圆弧左上角的坐标。您的代码未居中的原因是您绘制弧线的方式。

g.fillArc(xCenter - largeRadius,yCenter - largeRadius,largeRadius,largeRadius,0,180);
g.fillArc(xCenter-(largeRadius+mediumRadius)/2,yCenter-(largeRadius+mediumRadius)/2,mediumRadius,mediumRadius,0,180);
g.fillArc(xCenter-(largeRadius+smallRadius)/2,yCenter-(largeRadius+smallRadius)/2,smallRadius,smallRadius,0,180);

I took out a few of the excess stuff. You see how you're subtracting the (largeRadius+smallRadius)/2 and (largeRadius+mediumRadius)/2? This is shifting the rainbow to make it off center. What you should have is instead:

我取出了一些多余的东西。你知道你是如何减去 (largeRadius+smallRadius)/2 和 (largeRadius+mediumRadius)/2 的吗?这正在移动彩虹使其偏离中心。你应该拥有的是:

g.fillArc(xCenter - largeRadius/2,yCenter - largeRadius,largeRadius,largeRadius,0,180);
    g.fillArc(xCenter-(mediumRadius)/2,yCenter-(largeRadius+mediumRadius)/2,mediumRadius,mediumRadius,0,180);
    g.fillArc(xCenter-(smallRadius)/2,yCenter-(largeRadius+smallRadius)/2,smallRadius,smallRadius,0,180);

This will properly center the rainbow. Here's why.

这将使彩虹正确居中。这是为什么。

enter image description here

在此处输入图片说明

That's the point where they will start the drawing the arc from. If you want to center the entire rainbow, you'd shift it over by half of it's entire width. So if you want to center the red arc, you'd do

这就是他们开始绘制弧的点。如果你想让整个彩虹居中,你可以将它移动整个宽度的一半。所以如果你想让红色弧线居中,你会这样做

xCenter - (largeRadius/2)

As this is setting the x start to the left by half. You wouldn't include largeRadius in the other arcs, as you're centering them around this point. Thus you'd want to shift them over by half of their individual widths, which is why their x positions are

因为这是将 x 开始设置为左侧一半。您不会在其他弧中包含 largeRadius,因为您将它们围绕这一点居中。因此,您希望将它们移动到各自宽度的一半,这就是为什么它们的 x 位置是

xCenter-(mediumRadius)/2
xCenter-(smallRadius)/2

Centering on the Y-axis works differently. You have to consider that the height of the rainbow overall is 1/4 the largeRadius. Your code uses yCenter = 3/4 * height, so that changes it a bit.

以 Y 轴为中心的工作方式不同。你必须考虑到彩虹整体的高度是 largeRadius 的 1/4。您的代码使用 yCenter = 3/4 * 高度,因此对其进行了一些更改。

This is my solution

这是我的解决方案

g.fillArc(xCenter - largeRadius/2,yCenter - largeRadius/2 + largeRadius/4 -height/4,largeRadius,largeRadius,0,180);
g.fillArc(xCenter-(mediumRadius)/2,yCenter-(mediumRadius)/2 + largeRadius/4 -height/4,mediumRadius,mediumRadius,0,180);
g.fillArc(xCenter-(smallRadius)/2,yCenter-(smallRadius)/2 + largeRadius/4 -height/4,smallRadius,smallRadius,0,180);

Let's take a look. I subtracted the largeRadius/2 (and respective radiuses) for the same principle as in x. But then I added largeRadius/4 because we have to shift the entire rainbow down. This is because subtracting the respective radius/2 only centers the rainbow as if it were an entire circle, not semi-circles.

让我们来看看。我减去了 largeRadius/2(和各自的半径),原理与 x 相同。但后来我添加了 largeRadius/4,因为我们必须将整个彩虹向下移动。这是因为减去相应的半径/2 只会使彩虹居中,就好像它是一个完整的圆,而不是半圆。

Adding largeRadius/4 shifts the rainbow down by overall half of it's height, centering it correctly for a semi-circle. Finally, subtracting height/4 makes changes the yCenter to height/2, since 3/4 * height is a requirement in your assignment.

添加 largeRadius/4 会将彩虹向下移动其高度的一半,使其正确居中为半圆。最后,减去 height/4 会使 yCenter 更改为 height/2,因为 3/4 * height 是您的作业要求。

Sorry about all the problems in the comments, hope this cleared it up.

对评论中的所有问题感到抱歉,希望这能解决问题。

回答by Robert P.

I've modified part of your code so you could get an idea. Remember that your xCenter and yCenter represent the center of your circle, not the coordinates you need to use in the fillArc method. The instructions you provided explain it pretty well. You can get an idea from what I did here and figure the rest by yourself.

我已经修改了你的部分代码,所以你可以得到一个想法。请记住,您的 xCenter 和 yCenter 表示圆的中心,而不是您需要在 fillArc 方法中使用的坐标。您提供的说明很好地解释了它。你可以从我在这里做的事情中得到一个想法,剩下的你自己来解决。

// First declare and initialize all radiuses
  int largeRadius = width/4;
  int smallRadius = height/4;
  int mediumRadius = (int) Math.sqrt(smallRadius * largeRadius);

//Then draw each arc in descending order from the largest one

g.setColor(Color.RED);

g.fillArc(xCenter-largeRadius,yCenter-largeRadius,largeRadius,largeRadius,0,180);

g.setColor(Color.GREEN);

g.fillArc(xCenter-(largeRadius+mediumRadius)/2,yCenter-(largeRadius+mediumRadius)/2,mediumRadius,mediumRadius,0,180);

g.setColor(Color.MAGENTA);

g.fillArc(xCenter-(largeRadius+smallRadius)/2,yCenter-(largeRadius+smallRadius)/2,smallRadius,smallRadius,0,180);

// Calculate the radius of the innermost (sky-color) semicircle

For you skyRadius consider:

对于您来说,skyRadius 考虑:

  1. Red width = large radius - medium radius
  2. green width = medium - small
  3. magenta width = small radius - skyradius
  1. 红色宽度 = 大半径 - 中等半径
  2. 绿色宽度 = 中 - 小
  3. 洋红色宽度 = 小半径 - 天空半径

if I did the math rightyou get: skyRadius = smallRadius - 2*(mediumRadius-smallRadius)+largeRadius-mediumRadius

如果我计算正确,你会得到:skyRadius = smallRadius - 2*(mediumRadius-smallRadius)+largeRadius-mediumRadius

int skRadius=smallRadius-2*(mediumRadius-smallRadius)+largeRadius-mediumRadius;
 g.setColor(skyColor);
 g.fillArc(xCenter-(largeRadius+skRadius)/2,yCenter-(largeRadius+skRadius)/2,skRadius,skRadius,0,180);

回答by Eric Roy

A much simpler equation for skyRadiusis:

一个更简单的方程skyRadius是:

int skyRadius = largeRadius - 3 * mediumRadius + 3 * smallRadius;