2016-04-09 16 views
0

Ich versuche, zufällig (noch nicht) Kreise auf einem JPanel durch Klicken auf ein JMenu zu malen. Ich benutze ein JTextField (und muss dies behalten) für einige Ausgaben. Hier ist meine Klasse:Verständnis Schwierigkeiten Java Swing

class RandomDrawer extends JPanel implements ActionListener { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     //double x = Math.random(); 
     //double y = Math.random(); 
     Random generator = new Random(); 
     int x = generator.nextInt(100)+1; 
     int y = generator.nextInt(100)+1; 
     //System.out.printf("x = %d y = %d\n", x, y); 
     status.setText(String.format("rnd draw x: %d y: %d", x, y)); 
     Graphics2D gg = (Graphics2D) canvas.getGraphics(); 
     gg.setColor(Color.BLACK); 
     gg.drawOval(50, 50, 50, 50); 
    } 
} 

Solange ich die Linie lassen

status.setText (String.format ("rnd Unentschieden x:% d y:% d", x, y));

bleiben Sie dort, ich bekomme nichts gezeichnet. Ohne es verstehe ich meinen Kreis, ich bin mir nicht sicher, was das Problem ist. Ich kann nicht herausfinden, warum nichts gezeichnet wird.

Vielen Dank

EDIT:

Hallo, ich versuchte, die gegebenen Informationen zu verstehen. Leider muss ich mit der Graphics2D Klasse zeichnen, also kann ich nicht mit Formen zeichnen. Also habe ich es versucht, leider wird es noch nicht zeichnen, kannst du mir ein paar Tipps geben? Ich habe versucht, eine neue Klasse DrawShape zu erstellen, mein Gedanke war, dass ich mit diesen Objekten den Überblick behalten konnte. In meinem Verständnis sollte es jetzt ein gezogenes Oval sein
gg.drawOval (100,100,100,100);

Vielen Dank.

class DrawShape { 
    public DrawShape(String string) { 
     // TODO Auto-generated constructor stub 
    } 
} 

class RandomDrawer extends JPanel implements ActionListener { 
    /* (non-Javadoc) 
    * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) 
    */ 
    private List<DrawShape> shapes = new ArrayList<DrawShape>(); 


    public void addShape(DrawShape s) { 
     shapes.add(s); 
     repaint(); 
    } 


    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     final Graphics2D gg = (Graphics2D) g; 
     gg.setColor(Color.BLACK); 
     gg.drawOval(100, 100, 100, 100); 
    } 


    @Override 
    public void actionPerformed(ActionEvent e) { 
     Random generator = new Random(); 
     int x = generator.nextInt(100)+100; 
     int y = generator.nextInt(100)+100; 

     if (e.getActionCommand()==("Draw RandomCircle")) { 
      System.out.printf("x = %d y = %d\n", x, y); 
      status.setText(String.format("rnd draw x:%d y:%d ", x, y)); 
      DrawShape circle = new DrawShape("Circle"); 
      addShape(circle); 
      int count = shapes.size(); 
      System.out.printf("objects in array: %d\n", count); 
     } 

     else if (e.getActionCommand()==("Draw RandomRectangle")) { 
      System.out.printf("x = %d y = %d\n", x, y); 
      //status.setText(String.format("rnd draw x: y: ")); 
      //Graphics2D gg = (Graphics2D) canvas.getGraphics(); 
      //gg.setColor(Color.BLACK); 
      //gg.drawRect(x, y, generator.nextInt(x), generator.nextInt(y)); 
     } 
    } 
} 

Antwort

2

Malen und so passiert ereignisgesteuert. Wenn ein Stück einer Komponente neu gezeichnet werden muss, wird die paintComponent Methode aufgerufen.

Dies bedeutet, dass Sie eine Komponente benötigen, die nows, wie zum Beispiel zeichnen durch:

public class DrawShape { 

    public final String text; 
    public final Color color; 
    public final Shape shape; 

    public DrawShape(String text, Color color, Shape shape) { 
     this.text = text; 
     this.color = color; 
     this.shape = shape; 
    } 
} 

public class CanvasWithShapes extends JPanel { 

    private List<DrawShape> shapes = new ArrayList<>(); 

    public void addShape(DrawShape shape) { 
     shapes.add(shape); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     final Graphics2D gg = (Graphics2D) g; 
     // Java 8: shapes.stream().forEach((shape) -> gg.draw(shape)); 
     for (DrawShape drawShape : shapes) { 
      gg.setColor(drawShape.color); 
      gg.draw(drawShape.shape); 
      Rectangle bounds = shape.getBounds(); 
      gg.drawString(shape.text, bounds.x+ 10, bounds.y + 20); 
     } 
    } 
} 

Und dann Formen fügen Sie einfach ein wenig später neu gezeichnet werden.

Shape oval = ...; 
c.add(oval); 
c.repaint(50L); // A bit later 

Detailliertere

A Shape viele Implementierungen von Interesse wie Rechteck und Oval hat. Graphics2D kann eine Form zeichnen und ausfüllen. In diesem Fall wäre es ideal, eine solche Form hinzuzufügen. Vielleicht zusammen mit Farbe und Text. Also habe ich Ihre DrawShape-Klasse genommen, um diese Eigenschaften zu halten.

Random generator = new Random(); 
    int x = generator.nextInt(100)+100; 
    int y = generator.nextInt(100)+100; 

    if (e.getActionCommand().equals("Draw RandomCircle")) { 
     System.out.printf("x = %d y = %d\n", x, y); 
     status.setText(String.format("rnd draw x:%d y:%d ", x, y)); 
     int w = generator.nextInt(100) + 10; 
     int h = w; 
     Shape circle = new Ellipse2D.Double(x, y, w, h); 
     addShape(new DrawShape(text, Color.BLACK, circle)); 
     int count = shapes.size(); 
     System.out.printf("objects in array: %d\n", count); 
    } else if (e.getActionCommand().equals("Draw RandomRectangle")) { 
     System.out.printf("x = %d y = %d\n", x, y); 

generator.nextInt (y)); int w = Generator.nextInt (100) + 10; int h = Generator.nextInt (100) + 10; Form rect = Rectangle2D.Double (x, y, w, h) addShape (neue DrawShape (Text, Color.BLACK, rect)); }

+0

danke für deinen Kommentar, ich habe meine Herangehensweise geändert, kannst du bitte einen Blick darauf werfen und mir ein paar Tipps geben? – Kaw

2

Graphics2D gg = (Graphics2D) canvas.getGraphics();

Verwenden Sie nicht die getGraphics() - Methode, um zu malen. Das Gemälde ist vorübergehend. Es wird verloren gehen, wenn Sie den Rahmen zum Beispiel ändern.

Stattdessen müssen Sie die paintComponent() Methode Ihres Panels überschreiben.

Wenn Sie mehrere Objekte malen möchten, müssen Sie jedes Objekt verfolgen. Schauen Sie sich Custom Painting Approaches für die beiden gemeinsamen Möglichkeiten, dies zu tun:

  1. Frieds Liste der Objekte zu malen und dann durchlaufen die Liste jedes Mal, wenn die Komponente neu gezeichnet wird.
  2. malen Sie das Objekt direkt zu einem BufferedImage und malen Sie dann das BufferedImage.

Das Beispiel malt Rechtecke. Im Grunde benötigen Sie eine Methode wie die addRectangle(...) Methode, um ein neues Objekt zu malen. Jedes Mal, wenn Sie auf die Schaltfläche klicken, fügen Sie die neue zufällige Form hinzu.

+0

Danke für Ihre Antwort camickr, ich werde das versuchen. Aber das beantwortet meine Frage nicht, ich werde paintComponent() ausprobieren. Aber trotzdem, y funktioniert es nicht so? Sagen wir mal zum Verständnis. – Kaw

+0

@Kaw, Die 'setText()' Methode bewirkt, dass der Frame neu gezeichnet wird. Da jedes Gemälde, das du mit getGraphics machst, nur vorübergehend ist, verlierst du das Bild des Ovals, wenn der Rahmen neu gestrichen wird. Dies entspricht der Größenänderung des Rahmens. – camickr

2

Vermutlich stammt Ihr Problem von der setText() Aufruf das Objekt Graphics auf eine unerwartete Weise zu ändern. Es ist selten angemessen, getGraphics() in Ihrem eigenen Code zu verwenden. Malen Sie stattdessen mit der Graphics, die Ihnen gegeben wird.

Ihr Ansatz ist sowieso fehlerhaft. Wenn es Ihnen gelingt, eine GUI-Komponente nur einmal zu zeichnen, während Sie dies versuchen, verschwindet das, was Sie gezeichnet haben, wenn die Komponente neu gezeichnet wird. Eine Neulackierung kann aus einer Vielzahl von Gründen erfolgen, von denen viele nichts mit dem eigenen Verhalten des Programms zu tun haben.

Was Sie tun müssen, ist eine Art von Daten zu speichern, die die paintComponent()-Methode der Komponente verlassen wird, um Ihre benutzerdefinierte Malerei jedes Mal zu tun. Daraus folgt, dass Sie die Methode paintComponent() der Komponente überschreiben müssen, auf der die Kreise gezeichnet werden sollen. Sie könnten beispielsweise eine Klasse erstellen, die alle benötigten Zeichnungsdetails für einen Kreis aufzeichnet, und RandomDrawer eine List dieser Objekte als eine Elementvariable angeben. Der Aktionslistener manipuliert diese Liste entsprechend und plant eine Neubemalung, und paintComponent() wird außer Kraft gesetzt, um das tatsächliche Malen durchzuführen.