2015-04-02 59 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; 
}