2013-01-03 233 views
1

我正在使用java指南針。首先,我爲我的指南針創建了一個用戶界面原型,並創建了一個可用的SSCCE,在那裏你可以點擊面板,指針指向另一個方向,大約相差15度。這是代碼:指南針指針位置錯誤

public class TestFrame extends JFrame { 

    public TestFrame() { 
     initComponents(); 
    } 

    public void initComponents() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setLocation(new Point((int) (Toolkit.getDefaultToolkit().getScreenSize().width/2) - 400, (int) (Toolkit.getDefaultToolkit().getScreenSize().height/2) - 250)); 
     setSize(500, 500); 
     setVisible(true); 
     CompassPanel c = new CompassPanel(); 
     add(c, BorderLayout.CENTER); 

    } 

    public class CompassPanel extends JPanel { 
     Image bufImage; 
     Graphics bufG; 
     private int circleX, circleY, circleRadius; 
     private int[] xPoints, yPoints; 
     private double rotationAngle = Math.toRadians(0); 

     public CompassPanel() { 
      setVisible(true); 

      addMouseListener(new MouseListener() { 
       @Override 
       public void mouseReleased(MouseEvent e) { 
       } 

       @Override 
       public void mousePressed(MouseEvent e) { 
       } 

       @Override 
       public void mouseExited(MouseEvent e) { 
       } 

       @Override 
       public void mouseEntered(MouseEvent e) { 
       } 

       @Override 
       public void mouseClicked(MouseEvent e) { 
        rotationAngle = rotationAngle + Math.toRadians(15); 
        repaint(); 
       } 
      }); 

     } 

     @Override 
     public void paint(Graphics g) { 
      super.paint(g); 
      Graphics2D g2d = (Graphics2D) g; 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
      circleRadius = (int) (getWidth() * 0.7); 
      circleX = 50; 
      circleY = 50; 

      g2d.setColor(Color.BLACK); 
      for (int angle = 0; angle <= 360; angle += 5) { 
       double sin = Math.sin(Math.toRadians(angle)); 
       double cos = Math.cos(Math.toRadians(angle)); 
       int x1 = (int) ((circleX + circleRadius/2) - cos * (circleRadius * 0.37) - sin * (circleRadius * 0.37)); 
       int y1 = (int) ((circleY + circleRadius/2) + sin * (circleRadius * 0.37) - cos * (circleRadius * 0.37)); 
       g2d.setColor(Color.BLACK); 
       g2d.drawLine(x1, y1, (circleX + circleRadius/2), (circleY + circleRadius/2)); 
      } 

      g2d.setFont(new Font("Arial", Font.BOLD, 11)); 
      g2d.drawString("WEST", circleX - 45, circleY + circleRadius/2 + 4); 
      g2d.drawString("EAST", circleX + circleRadius + 13, circleY + circleRadius/2 + 4); 
      g2d.drawString("NORTH", circleX + circleRadius/2 - 14, circleY - 15); 
      g2d.drawString("SOUTH", circleX + circleRadius/2 - 14, circleY + circleRadius + 25); 
      g2d.setColor(Color.WHITE); 
      g2d.fillOval(circleX, circleY, circleRadius, circleRadius); 
      g2d.setColor(Color.BLACK); 
      g2d.drawOval(circleX, circleY, circleRadius, circleRadius); 

      xPoints = new int[] { (int) (circleX + circleRadius/2), 
        (int) (circleX + circleRadius * 0.25), 
        (int) (circleX + circleRadius/2), 
        (int) (circleX + circleRadius * 0.75) }; 

      yPoints = new int[] { (int) (circleY + 30), 
        (int) (circleY + circleRadius * 0.85), 
        (int) (circleY + circleRadius * 0.6), 
        (int) (circleY + circleRadius * 0.85) }; 

      Polygon fillPoly = new Polygon(xPoints, yPoints, 4); 
      Polygon outerPoly = new Polygon(xPoints, yPoints, 4); 

      int rotationX = circleX + (circleRadius/2); 
      int rotationY = circleX + (circleRadius/2); 

      g2d.setColor(Color.green); 
      g2d.fillOval(rotationX, rotationY, 5, 5); 

      AffineTransform a = g2d.getTransform().getRotateInstance(rotationAngle, rotationX, rotationY); 
      g2d.setTransform(a); 

      g2d.setColor(Color.RED); 
      g2d.fillPolygon(fillPoly); 

      g2d.setColor(Color.black); 
      g2d.draw(outerPoly); 
     } 

     @Override 
     public void update(Graphics g) { 
      int w = this.getSize().width; 
      int h = this.getSize().height; 

      if (bufImage == null) { 
       bufImage = this.createImage(w, h); 
       bufG = bufImage.getGraphics(); 
      } 

      bufG.setColor(this.getBackground()); 
      bufG.fillRect(0, 0, w, h); 
      bufG.setColor(this.getForeground()); 

      paint(bufG); 
      g.drawImage(bufImage, 0, 0, this); 
     } 

     public void setRotationAngle(int angle) { 
      rotationAngle = angle; 
     } 
    } 

    public static void main(String[] args) { 
     new TestFrame(); 
    } 
} 

當我將此面板應用到我的應用程序中時,針沒有被繪製,因爲它在SSCCE中。它被繪製得更高一些,位置的左邊是它的意思。當我點擊面板並旋轉針時,旋轉工作正常,並且針被塗在它所屬的位置。

我將這樣的面板添加到我的應用程序中。 sensorPanel是JPanelTabbedPane

public JPanel createSensorPanel(){ 
    sensorPanel = new JPanel(new MigLayout("fill, insets 3")); 
    CompassPanel compassPanel = new CompassPanel(); 
    sensorPanel.add(compassPanel, "wrap"); 
    return sensorPanel; 
} 

爲什麼針的Polygon不是它在SSCCE繪製位置繪製?

編輯:

這是一個問題的圖片。 picture

+0

你可以發佈一個屏幕截圖的問題..? – Sorceror

+0

'setLocation(。新點((int)的(Toolkit.getDefaultToolkit()getScreenSize()寬度/ 2) - 。400,(INT)(Toolkit.getDefaultToolkit()getScreenSize()高度/ 2) - 250)) ; setSize(500,500);'用'setLocationByPlatform(true)替換那個批次;'結果可以看到[here](http://stackoverflow.com/a/7143398/418556)。 –

回答

2

如果你仔細觀察圖像上發生的變化,你會發現仿射變換是問題。

enter image description here

貌似仿射變換涉及頂級父不是當前的子組件(見java Affine Transform correct order)。

的快速和骯髒的解決辦法是翻譯的箭頭父母被翻譯(基於this answer

AffineTransform a = g2d.getTransform(). 
    getRotateInstance(rotationAngle, rotationX, rotationY) 
    .translate(parent.getX(), parent.getY()) // use instance of real parent instead 
    .translate(tabpane.getX(), tabpane.getY()); // use instance of JTabbedPane instead 

可是方便多了會出現一些常見的解決方案,像this one