绘制抗锯齿形状并用Java旋转它们

时间:2013-06-29 20:50:03

标签: java java-7

背景

我是Java新手,今天我开始学习它(使用thenewboston.org)。我已经知道如何制作简单的windows / forms / gui,如何绘制线条等。

我的目标是在Java中创建这样的表:

enter image description here

这是我在.NET C#WPF中创建的标尺,现在我想将其重写为Java。

主要问题

如何创建具有一定透明度的三角形或其他形状并旋转它?

我尝试使用这样的Graphics对象绘制一些东西:

public void paint(Graphics g){
   g.drawLine(0, 0, 100, 100);
}

但我认为这是错误的方向,因为当我在图形上放置东西时 - 它只是停留在那里,我无法移动或旋转它。

我必须清除整个图形并再次绘制它以制作一种“动画”,还是有更简单的方法?


编辑: 我已经知道如何抗锯齿了(Hovercraft Full Of Eels已经帮助了我 - 谢谢)。


EDIT2:

我的代码实际上是这样的:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MainWindow extends JPanel {

    private Point p1 = new Point(100, 100);
    private Point p2 = new Point(740, 450);

    public MainWindow() {
        this.setPreferredSize(new Dimension(800, 600));
    }

    @Override
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);
        drawLines(g);
    }

    private void drawLines(Graphics g)
    {
        Graphics2D g2d = (Graphics2D) g;

        g2d.setColor(Color.DARK_GRAY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);     
        g2d.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));

        g.drawLine(p1.x, p1.y, p2.x, p2.y);

    }

    private void display() {
        JFrame f = new JFrame("Main Window");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {

        new MainWindow().display();
    }

}

2 个答案:

答案 0 :(得分:5)

你说:

  

我尝试使用这样的Graphics对象绘制一些东西:

public void paint(Graphics g){
   g.drawLine(0, 0, 100, 100);
}
     

但我认为这是错误的方向,因为当我在图形上放置东西时 - 它只是停留在那里,我无法移动或旋转它。

     

我必须清除整个图形并再次绘制它以制作一种“动画”,还是有更简单的方法?

建议:

  • 不要对您的号码进行硬编码。请改用类字段(变量),以便程序可以轻松更改项目的位置。
  • 不要覆盖组件的paint(...)方法。而是覆盖从JComponent或其子项之一(如JPanel)派生的对象的paintComponent(Graphics g)方法。这将为您提供自动双缓冲的优势,使动画更流畅,并且还可以减少错误绘制组件的子项或边框的可能性。
  • 将Graphics对象转换为Graphics2D对象,以便您可以使用实现Shape接口的类进行更高级的绘制,包括Rectangle2D,Ellipse2D,Line2D,Path2D等等。
  • 使用Graphics#drawImage(...)方法将背景图像绘制为BufferedImage,然后在此基础上绘制运动图像,再次使用Graphics2D对象并再次根据对象的状态更改绘制的图像(值由其领域持有)。
  • 在做动画时要小心你遵守Swing线程规则,你没有任何动画或游戏循环占用Swing线程。 Swing Timer可以让你创建一个快速简单的游戏循环(尽管有点原始)。

例如:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class DailAnimation extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = 350;
   private static final Point2D CENTER = new Point2D.Double(PREF_W / 2.0,
         PREF_W / 2.0);
   private static final double RADIUS = PREF_W / 2.0;
   private static final Color LARGE_TICK_COLOR = Color.green;
   private static final Color CENTER_HUB_COLOR = Color.LIGHT_GRAY;
   private static final Stroke LARGE_TICK_STROKE = new BasicStroke(3f);
   private static final int LRG_TICK_COUNT = 9;
   private static final double TOTAL_LRG_TICKS = 12;
   private static final double LRG_TICK_OUTER_RAD = 0.9;
   private static final double LRG_TICK_INNER_RAD = 0.8;
   private static final int START_TICK = 10;
   private static final double CENTER_HUB_RADIUS = 10;
   public static final int MAX_SPEED = 100;
   private static final double INIT_SPEED = 0;
   private static final double DIAL_INNER_RAD = 0.02;
   private static final double DIAL_OUTER_RAD = 0.75;
   private static final Color DIAL_COLOR = Color.DARK_GRAY;
   private BufferedImage backgroundImg;

   private double speed;
   private double theta;
   private double cosTheta;
   private double sinTheta;

   public DailAnimation() {
      setBackground(Color.white);

      backgroundImg = createBackgroundImg();
      setSpeed(INIT_SPEED);
   }

   public void setSpeed(double speed) {
      if (speed < 0) {
         speed = 0;
      } else if (speed > MAX_SPEED) {
         speed = MAX_SPEED;
      }
      this.speed = speed;
      this.theta = ((speed / MAX_SPEED) * LRG_TICK_COUNT * 2.0 + START_TICK)
            * Math.PI / TOTAL_LRG_TICKS;
      cosTheta = Math.cos(theta);
      sinTheta = Math.sin(theta);

      repaint();
   }

   private BufferedImage createBackgroundImg() {
      BufferedImage img = new BufferedImage(PREF_W, PREF_H,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = img.createGraphics();

      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setColor(LARGE_TICK_COLOR);
      g2.setStroke(LARGE_TICK_STROKE);

      for (int i = 0; i < LRG_TICK_COUNT; i++) {
         double theta = (i * 2.0 + START_TICK) * Math.PI / TOTAL_LRG_TICKS;
         double cosTheta = Math.cos(theta);
         double sinTheta = Math.sin(theta);

         int x1 = (int) (LRG_TICK_INNER_RAD * RADIUS * cosTheta + CENTER.getX());
         int y1 = (int) (LRG_TICK_INNER_RAD * RADIUS * sinTheta + CENTER.getY());
         int x2 = (int) (LRG_TICK_OUTER_RAD * RADIUS * cosTheta + CENTER.getX());
         int y2 = (int) (LRG_TICK_OUTER_RAD * RADIUS * sinTheta + CENTER.getY());

         g2.drawLine(x1, y1, x2, y2);
      }

      g2.setColor(CENTER_HUB_COLOR);

      int x = (int) (CENTER.getX() - CENTER_HUB_RADIUS);
      int y = (int) (CENTER.getY() - CENTER_HUB_RADIUS);
      int width = (int) (2 * CENTER_HUB_RADIUS);
      int height = width;
      g2.fillOval(x, y, width, height);
      // g2.draw(ellipse);

      g2.dispose();
      return img;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (backgroundImg != null) {
         g.drawImage(backgroundImg, 0, 0, this);
      }

      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

      g.setColor(DIAL_COLOR);
      int x1 = (int) (DIAL_INNER_RAD * RADIUS * cosTheta + CENTER.getX());
      int y1 = (int) (DIAL_INNER_RAD * RADIUS * sinTheta + CENTER.getY());
      int x2 = (int) (DIAL_OUTER_RAD * RADIUS * cosTheta + CENTER.getX());
      int y2 = (int) (DIAL_OUTER_RAD * RADIUS * sinTheta + CENTER.getY());

      g.drawLine(x1, y1, x2, y2);

   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private static void createAndShowGui() {
      final DailAnimation mainPanel = new DailAnimation();

      JFrame frame = new JFrame("DailAnimation");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);

      int delay = 100;
      new Timer(delay, new ActionListener() {
         int speed = 0;

         @Override
         public void actionPerformed(ActionEvent evt) {
            speed ++;
            if (speed > DailAnimation.MAX_SPEED) {
               ((Timer)evt.getSource()).stop();
            }
            mainPanel.setSpeed(speed);
         }
      }).start();
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

答案 1 :(得分:0)

通过Graphics.drawLine()绘制一条直接将像素写入支持Graphics实例的任何内容。如果要旋转线条,则必须计算旋转时其坐标应该是什么。这是在AWT和Swing中绘制东西的唯一方法。

您可以编写一个保持其角度的针类,然后让它每帧处理它的渲染。