2015-06-22 37 views
-1

我试图用Swing 2d绘制一些可旋转的箭头,网上有一些示例代码,所以我复制并将它们组合成一个应用程序,但是这三种方法中的每一种都存在错误:第一种不旋转从它的中心,另外两个在箭头中看起来不正确,有人能告诉我如何解决它们吗?如何用Java Swing绘制二维箭头?

import java.awt.*; 
import java.awt.geom.*; 
import javax.swing.*; 
import javax.swing.event.*; 

public class Arrow_Test extends JPanel implements ChangeListener { 
    Path2D.Double arrow = createArrow(); 
    double theta = 0; 

    public void stateChanged(ChangeEvent e) { 
     int value = ((JSlider) e.getSource()).getValue(); 
     theta = Math.toRadians(value); 
     repaint(); 
    } 

    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D) g; 
     g2.setStroke(new BasicStroke(6)); 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
       RenderingHints.VALUE_ANTIALIAS_ON); 
     int cx = getWidth()/2; 
     int cy = getHeight()/2; 
     AffineTransform at = AffineTransform.getTranslateInstance(cx, cy); 
     at.rotate(theta); 
     at.scale(2.0, 2.0); 
     Shape shape = at.createTransformedShape(arrow); 
     g2.setPaint(Color.blue); 
     g2.draw(shape); 

     GeneralPath a = drawArrow(20, 20, 30, 20, 50, 13); 
     AffineTransform at1 = AffineTransform.getTranslateInstance(cx, cy); 
     at1.rotate(theta); 
     at1.scale(2.0, 2.0); 
     Shape shape1 = at1.createTransformedShape(a); 
     g2.setPaint(Color.blue); 
     g2.draw(shape1); 

     drawArrow(100, 100, 50, 0, g2); 
    } 

    private Path2D.Double createArrow() { 
     int length = 80; 
     int barb = 15; 
     double angle = Math.toRadians(20); 
     Path2D.Double path = new Path2D.Double(); 
     path.moveTo(-length/2, 0); 
     path.lineTo(length/2, 0); 
     double x = length/2 - barb * Math.cos(angle); 
     double y = barb * Math.sin(angle); 
     path.lineTo(x, y); 
     x = length/2 - barb * Math.cos(-angle); 
     y = barb * Math.sin(-angle); 
     path.moveTo(length/2, 0); 
     path.lineTo(x, y); 
     return path; 
    } 

    GeneralPath drawArrow(int x1, int y1, int x2, int y2, double length, 
      double width) { 
     double x, y; 
     length = 50; 
     width = 5; 

     Point2D start = new Point2D.Double(x1, y1); 
     Point2D end = new Point2D.Double(x2, y2); 
     Point2D base = new Point2D.Double(); 
     Point2D back1 = new Point2D.Double(); 
     Point2D back2 = new Point2D.Double(); 

     length = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); 

     // Compute normalized line vector 
     x = (x2 - x1)/length; 
     y = (y2 - y1)/length; 
     // Compute points for arrow head 
     base.setLocation(x2 - x * length, y2 - y * length); 
     back1.setLocation(base.getX() - width * y, base.getY() + width * x); 
     back2.setLocation(base.getX() + length * y, base.getY() - width * x); 

     Line2D.Double l1 = new Line2D.Double(start, end); 
     Line2D.Double l2 = new Line2D.Double(end, back2); 
     Line2D.Double l3 = new Line2D.Double(end, back1); 

     GeneralPath c = new GeneralPath(GeneralPath.WIND_EVEN_ODD); 
     c.append(l1, true); 
     c.append(l2, true); 
     c.append(l3, true); 

     return c; 
    } 

    private void drawArrow(int x1, int y1, int x2, int y2, Graphics2D g2d) { 

     int x[] = { 0, 36, 0 }; 
     int y[] = { -10, 0, 10 }; 

     g2d.rotate(theta); 
     g2d.drawLine(x1 - 20, y1, x1 + 20, y1); 
     // will move the orgin 
     g2d.translate(x1, y1); 
     double angle = findLineAngle(x1 - 20, y1, x1 + 20, y1); 
     System.out.println("angle is===>" + angle); 
     g2d.rotate(angle); 

     g2d.fillPolygon(new Polygon(x, y, 3)); 
     // /will restore orgin 
     g2d.translate(-x2, -y2); 
     g2d.rotate(-angle); 
    } 

    private double findLineAngle(int x1, int y1, int x2, int y2) { 
     if ((x2 - x1) == 0) 
      return Math.PI/2; 
     return Math.atan((y2 - y1)/(x2 - x1)); 
    } 

    private JSlider getSlider() { 
     JSlider slider = new JSlider(-180, 180, 0); 
     slider.addChangeListener(this); 
     return slider; 
    } 

    public static void main(String[] args) { 
     Arrow_Test test = new Arrow_Test(); 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(test); 
     f.add(test.getSlider(), "Last"); 
     f.setSize(400, 400); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 
+0

这个问题可以读取一个可运行的例子太像,“请修复我找到的代码”。为了改善这一点,可以考虑告诉我们关于你发现的**概念**,你已经**如何尝试合并和修复它们,以及它们如何不适合你。换句话说,请考虑向我们展示**你的努力的成果,根据借来的概念编写自己的箭头,而不是借用代码。 –

+0

小心,转换正在复合 – MadProgrammer

回答

4

我真的不想进入“为什么”,因为你的代码很难读取。

当旋转一个对象时,你应该指定一个锚点(x/y),在这个锚点周围进行旋转。默认情况下,这是当前上下文的0x0位置。

当你的“路径”基础箭头看起来......有趣的,可能与他们创建的方式有关,但我没有真正玩弄它们。

你要小心的另一件事是,转换是复利,这是一个好和坏的事情,你只需要小心当他们;)

让我们先从基本形状...

public class Arrow extends Path2D.Double { 

    public Arrow() { 
     moveTo(0, 10); 
     lineTo(36, 10); 
     moveTo(36 - 16, 0); 
     lineTo(36, 10); 
     moveTo(36 - 16, 20); 
     lineTo(36, 10); 
    } 

} 

好吧,没有什么令人印象深刻的,您可以添加宽度/高度参数,使箭头以您想要的方式显示,但是这会得到一个基本的开始。我更喜欢使用基于Shape的对象,它们只是更简单地与旧的Polygon风格的API一起工作。

Arrow基本上是三条线在水平线的垂直和水平线的中间相遇。你可能会得到一个更好的结果,如果箭头是单行线,但我会离开,为了让您与

下玩,我们需要定位和旋转对象(arrowArrow实例BTW)

double x = (getWidth() - arrow.getBounds().getWidth())/2d; 
double y = (getHeight() - arrow.getBounds().getHeight())/2d; 

AffineTransform at = new AffineTransform(); 
at.translate(x, y); 
at.rotate(theta, arrow.getBounds().getWidth()/2d, arrow.getBounds().getHeight()/2d); 
g2d.setTransform(at); 

g2d.draw(arrow); 

我们先申请一个翻译,这使得它,以便Graphics上下文的0x0现在的位置是我们指定x/y位置。这使得它更容易计算锚位置周围的箭头应转动......

并绑定它一起

Arrow

import java.awt.BasicStroke; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Path2D; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JSlider; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class Arrow_Test extends JPanel implements ChangeListener { 

    double theta = 0; 
    Path2D arrow = new Arrow(); 

    public void stateChanged(ChangeEvent e) { 
     int value = ((JSlider) e.getSource()).getValue(); 
     theta = Math.toRadians(value); 
     repaint(); 
    } 

    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2d = (Graphics2D) g; 

     g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
     g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
     g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
     g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 

     g2d.setStroke(new BasicStroke(4)); 

     double x = (getWidth() - arrow.getBounds().getWidth())/2d; 
     double y = (getHeight() - arrow.getBounds().getHeight())/2d; 

     AffineTransform at = new AffineTransform(); 
     at.translate(x, y); 
     at.rotate(theta, arrow.getBounds().getWidth()/2d, arrow.getBounds().getHeight()/2d); 
     g2d.setTransform(at); 

     g2d.draw(arrow); 
     g2d.dispose(); 
    } 

    private JSlider getSlider() { 
     JSlider slider = new JSlider(-180, 180, 0); 
     slider.addChangeListener(this); 
     return slider; 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       Arrow_Test test = new Arrow_Test(); 
       JFrame f = new JFrame(); 
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       f.add(test); 
       f.add(test.getSlider(), "Last"); 
       f.setSize(400, 400); 
       f.setLocationRelativeTo(null); 
       f.setVisible(true); 
      } 
     }); 
    } 

    public class Arrow extends Path2D.Double { 

     public Arrow() { 
      moveTo(0, 10); 
      lineTo(36, 10); 
      moveTo(36 - 16, 0); 
      lineTo(36, 10); 
      moveTo(36 - 16, 20); 
      lineTo(36, 10); 
     } 

    } 
} 
+0

谢谢,很好地完成! – Frank

+0

很高兴它可以帮助 – MadProgrammer