2015-04-02 99 views
2

我編寫了一個Java程序,根據用戶執行的按鈕單擊,採用三角形進行旋轉,移位或旋轉並對其進行移位。Java GUI窗口顯示垃圾

在此之前,我指示用戶輸入邏輯座標範圍以確定像素座標如何映射到實際x-y座標系。

最初,我有出現在屏幕的中間的三角形,和一個按鈕被點擊後,在一定的操作在其上預先形成後示出的三角形(即旋轉,移位等)

但是,在完成操作並重繪三角形之後,我會在JPanel的左上角看到一個輸入框。

我不知道這是如何不斷繪製在那裏。

代碼:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 

public class RotateAndShiftTriangles extends JFrame { 
    public static void main(String[] args) { new RotateAndShiftTriangles(); } 

    RotateAndShiftTriangles() { 
     super("Drawing 50 Triangles"); 

     final JPanel drawingPanel = new DrawTriangles(); 
     JPanel buttonPanel = new JPanel(); 
     JButton rotate = new JButton("Rotate"), 
       shift = new JButton("Shift"), 
       rotateShift = new JButton("Rotate and Shift"), 
       reset = new JButton ("Reset"); 

     drawingPanel.setBackground(Color.WHITE); 

     buttonPanel.add(rotate); 
     buttonPanel.add(shift); 
     buttonPanel.add(rotateShift); 
     buttonPanel.add(reset); 

     addWindowListener(new WindowAdapter() { 
      public void windowClosing(WindowEvent e) { 
       System.exit(0); 
      } 
     }); 

     DrawTriangles.rWidth = Float.parseFloat(JOptionPane.showInputDialog("Input rWidth")); 
     DrawTriangles.rHeight = Float.parseFloat(JOptionPane.showInputDialog("Input rHeight")); 

     rotate.addActionListener(new ActionListener() { 

      public void actionPerformed(ActionEvent e) { 
       DrawTriangles.rotate = true; 
       drawingPanel.repaint(); 
      } 
     }); 

     shift.addActionListener(new ActionListener() { 

      public void actionPerformed(ActionEvent e) { 
       DrawTriangles.shift = true; 
       drawingPanel.repaint(); 
      } 
     }); 

     rotateShift.addActionListener(new ActionListener() { 

      public void actionPerformed(ActionEvent e) { 
       DrawTriangles.rotate = true; 
       DrawTriangles.shift = true; 
       drawingPanel.repaint(); 
      } 
     }); 

     reset.addActionListener(new ActionListener() { 

     @Override 
      public void actionPerformed(ActionEvent e) { 
       DrawTriangles.reset = true; 
       drawingPanel.repaint(); 
      } 
     }); 

     setSize(600, 400); 
     add("South", buttonPanel); 
     add("Center", drawingPanel); 
     setVisible(true); 
    } 
} 

class DrawTriangles extends JPanel { 
    static float rWidth, rHeight, pixelSize; 
    static int maxX, maxY, minMaxXY, centerX, centerY; 
    static boolean rotate = false, shift = false, reset = false; 
    float angle = 0; 

    void initialize() { 
     Dimension d = getSize(); 
     maxX = d.width - 1; maxY = d.height - 1; 
     pixelSize = Math.max(rWidth/maxX, rHeight/maxY); 
     minMaxXY = Math.min(maxX, maxY); 
     centerX = maxX/2; centerY = maxY/2; 
    } 

    public int iX2(float x) { return Math.round(x); } 
    public int iY2(float y) { return maxY - Math.round(y); } 
    public static int iX(float x) { return Math.round(centerX + x/pixelSize); } 
    public static int iY(float y) { return Math.round(centerY - y/pixelSize); } 
    public static float fx(int x) { return (x - centerX) * pixelSize; } 
    public static float fy(int y) { return (centerY - y) * pixelSize; } 

    public void paint(Graphics g) { 
     super.paintComponent(g); 
     initialize(); 

     int left = iX(-rWidth/2), right = iX(rWidth/2); 
     int top = iY(rHeight/2), bot = iY(-rHeight/2); 

     g.drawString("X: " + -rWidth/2 + " Y: " + rHeight/2, left, top + 10); 
     g.drawString("X: " + rWidth/2 + " Y: " + rHeight/2, right - 55, top + 10); 
     g.drawString("X: " + -rWidth/2 + " Y: " + -rHeight/2, left, bot); 
     g.drawString("X: " + rWidth/2 + " Y: " + -rHeight/2, right - 55, bot); 

     g.setColor(Color.BLUE); 
     g.drawRect(left, top, right - left, bot - top); 

     float side = 0.95f * minMaxXY, sideHalf = 0.5F * side, 
       h = sideHalf * (float)Math.sqrt(3), 
       xA, yA, xB, yB, xC, yC, 
       xA1, yA1, xB1, yB1, xC1, yC1, p, q; 

     q = 0.05F; 
     p = 1 - q; 

     xA = centerX - sideHalf; 
     yA = centerY - 0.5F * h; 
     xB = centerX + sideHalf; 

     yB = yA; 

     xC = centerX; 
     yC = centerY + 0.5F * h; 

     if(!reset) { 
      if(rotate) { 
       angle += Float.parseFloat(JOptionPane.showInputDialog("Input Angle of Rotation (in degrees)")); 
       float xR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Rotation"))), 
         yR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Rotation"))); 

       xA = rotateX(xA, yA, xR, yR, angle); 
       yA = rotateY(xA, yA, xR, yR, angle); 

       xB = rotateX(xB, yB, xR, yR, angle); 
       yB = rotateY(xB, yB, xR, yR, angle); 

       xC = rotateX(xC, yC, xR, yR, angle); 
       yC = rotateY(xC, yC, xR, yR, angle); 

       rotate = false; 
      } 
      if(shift) { 
       float xShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))), 
         yShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift"))); 

       xA += xShift; 
       yA += yShift; 

       xB += xShift; 
       yB += yShift; 

       xC += xShift; 
       yC += yShift; 

       shift = false; 
      } 
     } 

     g.setColor(Color.RED); 
     for (int i = 0; i < 50; i++) { 
      g.drawLine(iX2(xA), iY2(yA), iX2(xB), iY2(yB)); 
      g.drawLine(iX2(xB), iY2(yB), iX2(xC), iY2(yC)); 
      g.drawLine(iX2(xC), iY2(yC), iX2(xA), iY2(yA)); 

      if(i == 0) { 
       g.setColor(Color.BLACK); 
       g.drawString("A: X- " + xA + " Y- " + yA, 0, 50); 
       g.drawString("B: X- " + xB + " Y- " + yB, 0, 60); 
       g.drawString("C: X- " + xC + " Y- " + yC, 0, 70); 
       g.setColor(Color.RED); 
      } 

      xA1 = p * xA + q * xB; 
      yA1 = p * yA + q * yB; 
      xB1 = p * xB + q * xC; 
      yB1 = p * yB + q * yC; 
      xC1 = p * xC + q * xA; 
      yC1 = p * yC + q * yA; 

      xA = xA1; xB = xB1; xC = xC1; 
      yA = yA1; yB = yB1; yC = yC1; 
     } 
     if(reset) 
      angle = 0; 
     reset = false; 
    } 

    public float rotateX(float x, float y, float xR, float yR, float angle) { 
     angle *= (Math.PI/180.0); 
     float c = (float)Math.cos(angle), s = (float)Math.sin(angle), 
       xF = x - xR, yF = y - yR, 
       rx = xF * c - yF * s; 

     return rx + xR; 
    } 

    public float rotateY(float x, float y, float xR, float yR, float angle) { 
     angle *= (Math.PI/180.0); 
     float c = (float)Math.cos(angle), s = (float)Math.sin(angle), 
       xF = x - xR, yF = y - yR, 
       ry = xF * s + yF * c; 

     return ry + yR; 
    } 
} 

我不斷收到這個 Java GUI Garbage

+0

我將你的代碼複製到Eclipse編輯器中。當我輸入rWidth爲30,rHeight爲30,然後單擊旋轉按鈕時,代碼會異常終止。你太依賴靜態字段和JOptionPanels。使用InputPanel,DrawingPanel和ButtonPanel重新創建程序。根本不要使用任何靜態字段。 – 2015-04-02 16:45:56

+0

你忘了提到這個代碼從RepaintManager生成NPE和awfull異常, – mKorbel 2015-04-02 16:47:19

+0

爲什麼我不想使用靜態字段? – Delfino 2015-04-02 17:34:39

回答

3

你觸發JOptionPane彈出窗口裏面方法paint()

打電話給.paint()及其兄弟姐妹應該限制自己重繪對象,沒有別的。原因是,您的代碼會導致您的.paint()方法阻塞,直到彈出窗口關閉,然後繼續處理停止的位置,可能會拾取屏幕上仍然存在的工件。正如你在這裏看到的那樣,背景被繪製(通過調用super.paintComponent()),然後彈出窗口被繪製並關閉,然後你的.paint()方法的其餘部分運行,但由於背景已被繪製,所以沒有任何重新繪製彈出窗口的位置。

你應該像移動代碼:

angle += Float.parseFloat(JOptionPane.showInputDialog("Input Angle of Rotation (in degrees)")); 
float xR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Rotation"))), 
     yR = fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Rotation"))); 

float xShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))), 
     yShift = -fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift"))); 

出到合適的ActionListener方法,設置必要的值,然後從使用它們在你的paint()方法中。


你也應該瞭解如何使用.paint().paintComponent(),像@camickr表明,沒有一個方法調用它的兄弟姐妹的超級一致。

+0

1+,是的,showInputDialog是一個大問題,從來沒有這樣做。 – camickr 2015-04-02 17:42:38

3
public void paint(Graphics g) { 
    super.paintComponent(g); 

不知道這是否是唯一的問題,但是,風俗畫是通過覆蓋paintComponent()方法來完成:

public void paintComponent(Graphics g) { 
    super.paintComponent(g); 

編輯:

其他意見,不直接相關的問題,但對於適當的設計很重要:

add("South", buttonPanel); 
add("Center", drawingPanel); 

不要使用硬編碼文字。佈局管理器將提供您可以使用的變量。另外,不建議使用add(...)方法的形式(讀取API)。新形式是:

add(buttonPanel, BordeLayout.PAGE_END); 
add("Center", BorderLayout.CENTER); 

不要使用靜態方法和變量。如果你想改變你的類的屬性,然後創建「setter」方法。例如創建一個setter方法:

public void setRotate(Boolean rotate) 
{ 
    this.rotate = rotate 
    repaint(); 
} 

另外,不是setter方法調用repaint()方法。這是因爲您的自定義類(而不是使用類的代碼)應該負責重新繪製。

然後調用setter方法:

//DrawTriangles.rotate = true; // wrong 
drawingPanel.setRotate(true); 
+0

我嘗試用'paintComponent(Graphics g)'替換'paint(Graphics g)'',但仍然得到相同的結果:/ – Delfino 2015-04-02 15:57:24

+0

@Delfino,請參閱編輯。 – camickr 2015-04-02 17:52:12

+0

爲什麼我會選擇使用setter方法而不是靜態方法或變量?我不明白爲什麼使用靜態變量會在設計上造成負面影響。 – Delfino 2015-04-04 18:28:03

2

看起來是否顯示對話框這只是發生。我修改了代碼並對一些值進行了硬編碼,它的工作沒有問題。

if(!reset) { 
     if(rotate) { 
      angle += Float.parseFloat("15"); 
      float xR = fx(3), 
        yR = fx(3); 
      // other stuff... 
     } 

我建議你嘗試顯示對話框,並重繪組件之前設置相應的值,與此類似:

 shift.addActionListener(new ActionListener() { 

     public void actionPerformed(ActionEvent e) { 
      float xShift = -DrawTriangles.fx(Integer.parseInt(JOptionPane.showInputDialog("Input X Coordinate for Shift"))), 
        yShift = -DrawTriangles.fx(Integer.parseInt(JOptionPane.showInputDialog("Input Y Coordinate for Shift"))); 
      drawingPanel.xShift = xShift; 
      drawingPanel.yShift = yShift; 
      DrawTriangles.shift = true; 
      drawingPanel.repaint(); 
     } 
    }); 
0

使用的BufferedImage糾正圖紙,但仍然發生了異常。

public void paint(Graphics gg) { 
    BufferedImage bf = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); 

    Graphics2D g = bf.createGraphics(); 

    g.setColor(Color.WHITE); 
    g.fillRect(0, 0, getWidth(), getHeight()); 

... 

    gg.drawImage(bf, 0, 0, null); 

    if(reset) 
     angle = 0; 
    reset = false; 
}