4

背景

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

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

在此处输入图像描述

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

主要问题

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

我试图通过使用这样的 Graphics 对象来绘制一些东西:

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

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

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


编辑:我已经知道如何抗锯齿(充满鳗鱼的气垫船已经在这方面帮助了我 - 谢谢)。


编辑2:

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

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

}
4

2 回答 2

5

你说:

我试图通过使用这样的 Graphics 对象来绘制一些东西:

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

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

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

建议:

  • 不要硬编码你的数字。请改用类字段(变量),以便您的程序可以轻松更改绘制项目的位置。
  • 不要覆盖组件的paint(...)方法。而是覆盖paintComponent(Graphics g)从 JComponent 或其子对象之一(如 JPanel)派生的对象的方法。这将使您受益于自动双缓冲以获得更流畅的动画,并且还将减少错误绘制组件的子项或边框的可能性。
  • 将您的 Graphics 对象转换为 Graphics2D 对象,以便您可以使用实现 Shape 接口的类(包括 Rectangle2D、Ellipse2D、Line2D、Path2D 等)进行更高级的绘图。
  • 使用方法将背景图像绘制为 BufferedImage Graphics#drawImage(...),然后在此之上绘制运动图像,再次使用 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();
         }
      });
   }
}
于 2013-06-30T00:31:30.240 回答
0

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

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

于 2013-06-29T20:56:52.303 回答