2015-04-02 4 views
2

Я написал программу Java, чтобы взять треугольник и либо повернуть, сдвинуть, либо повернуть и сдвинуть его, основываясь на щелчке на кнопке, предварительно сформированном пользователем.Java GUI Window Displays Garbage

Предварительно я прошу пользователя ввести диапазоны логических координат, чтобы определить, как координаты пикселей будут отображаться в реальной системе координат 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. Не используйте никаких статических полей. –

+0

вы забыли упомянуть, что этот код генерирует NPE и awfull исключение из RepaintManager, – mKorbel

+0

Почему я не хочу использовать статические поля? – Delfino

ответ

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

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». Например создать сеттер метод:

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

Кроме того, не то, что метод сеттер вызывает метод перекрасить(). Это связано с тем, что ваш пользовательский класс (а не код, который использует класс) должен нести ответственность за выполнение перерисовки.

Затем вызовите метод установки:

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

Я попытался заменить 'paint (Graphics g)' на 'paintComponent (Graphics g)', но я все равно получаю тот же результат:/ – Delfino

+0

@Delfino, см. Правки. – camickr

+0

Почему я должен использовать методы setter вместо статических методов или переменных? Я не понимаю, почему существует недостаток в дизайне от использования статических переменных. – Delfino

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