2016-04-26 16 views
0

Ich hatte gehofft, dass mir jemand dabei helfen könnte. Ich kann wirklich niemanden finden, der genau dieses Problem beschreibt. In meiner Hauptklasse (Window), die JFrame erweitert, füge ich ein Objekt einer Klasse (Panel) hinzu, das JPanel erweitert und es meinem Rahmen hinzufügt.Artikel zu JPanel hinzugefügt, die nicht angezeigt werden

So weit so gut, alles in der JPanel Klasse zeigt mich, wie sie sollten, aber wenn ich in meiner Hauptklasse ShapeDef Objekt erstellen (verwendete Zahlen zu definieren und ziehen), und dann versuchen, es zu den Panel hinzuzufügen, die Zahlen werden nicht angezeigt. Warum? Ich versuchte mit revalidate() und repaint, aber es scheint nicht zu funktionieren.

Hier ist ein Teil des Codes:

Main-Klasse:

public class Window extends JFrame implements ActionListener{ 

private JPanel myPanel; 
private ShapeDef rect1, rect2; 

public Window(){ 
    super("Test Window"); 
    setLayout(new BorderLayout()); 

    myPanel = new Panel(new BorderLayout()); 
    myPanel.setBackground(Color.BLACK); 

    rect1 = new ShapeDef("Rectangle", Color.green, 200, 300, 20, 80); 
    rect2 = new ShapeDef("Rectangle", Color.BLUE, 300, 700, 50, 40); 
    myPanel.add(rect1); 
    myPanel.add(rect2); 

    add(myPanel, BorderLayout.CENTER); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
} 

public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
      JFrame myFrame = new PongInvaders(); 
      myFrame.setSize(1280, 720); 
      myFrame.setBackground(Color.BLACK); 
      myFrame.pack(); 
      myFrame.setVisible(true); 
     } 
    }); 
} 

ShapeDef Klasse:

public class ShapeDef extends JComponent{ 
    private final Color color; 
    private final int x, y, width, height; 
    private final String type; 

    public ShapeDef(String type, Color color, int x, int y, int width, int height){ 
     this.type = type; 
     this.color = color; 
     setBounds(x, y, width, height); 
     this.x = x; 
     this.y = y; 
     this.width = width; 
     this.height = height; 

    } 

     @Override 
     public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     if(type.equalsIgnoreCase("Rectangle")){ 
      g.setColor(color); 
      g.fillRect(0, 0, width, height); 
     } 
     else if(type.equalsIgnoreCase("Oval")){ 
      g.setColor(color); 
      g.fillOval(x, y, width, height); 
     } 
    } 
} 

Die aktuelle Version des von Keqiang Li vorgeschlagen Code zeichnet sowohl die Rechtecke , aber rect2 erscheint bei (0,0), während rect1 an den richtigen Koordinaten spawnt. Also im Grunde ist die Frage beantwortet, also vielen Dank für Ihre Hilfe. Aber warum spawnt nur eines der Rechtecke bei (0,0), während das andere bei gesetzten Koordinaten spawnt, wenn beide zum selben JPanel hinzugefügt werden?

@MadProgrammer Obwohl Ihre Antwort war nicht die, die ich erwartet habe, ich denke, es ist derjenige, den ich brauchte. Sie werden Ihrem Benutzernamen definitiv gerecht. Vielen Dank, dass Sie sich die Zeit genommen haben, mir etwas mehr über das Erstellen einer besseren Code-Struktur beizubringen.

Ich möchte auch darauf hinweisen, dass die anderen Antworten sehr hilfreich und aufschlussreich waren und dass sie mir auch viel beibrachten.

+0

fähig war Warum hat die Klasse "Panel" eine Constructor-Methode namens "RandomShape"? Und du willst wirklich Dinge für JPanel zeichnen, indem du die Methode "paintComponent" überschreibst? Es sieht besser aus, wenn Sie nur Etiketten oder andere Komponenten in einem 'JPanel' hinzufügen –

+0

Die andere Sache ist, es ist wirklich keine gute Übung, Ihre benutzerdefinierte Klasse die gleiche wie Java-Bibliothek Klasse, wie zum Beispiel" Panel "," Window " , füge dein eigenes Präfix hinzu. –

+0

Er zeichnet ausgefüllte Formen in der paintComponent-Methode. – FredK

Antwort

1

Persönlich denke ich, dass Sie die Lösung aus dem falschen Winkel nähern. Komponenten sind nicht wirklich dafür entwickelt, aber Sie können sie dazu bringen, es zu tun, aber es führt zu interessanten Pfaden, bei denen Sie bluten können, wenn Sie nicht aufpassen.

Stattdessen würde ich eine "grundlegende" Form definieren, die "bemalt" werden kann und aus, definieren Sie alle anderen Formen.

public interface Drawable { 
    public Color getStrokeColor(); 
    public Color getFillColor(); 
    public Rectangle getBounds(); 
    public void paint(Graphics2D g2d); 
} 

public abstract class AbstractDrawable implements Drawable { 

    private Color strokeColor; 
    private Color fillColor; 

    public AbstractDrawable(Color strokeColor, Color fillColor) { 
     this.strokeColor = strokeColor; 
     this.fillColor = fillColor; 
    } 

    @Override 
    public Color getStrokeColor() { 
     return strokeColor; 
    } 

    @Override 
    public Color getFillColor() { 
     return fillColor; 
    } 

} 

public class RectangleDrawable extends AbstractDrawable { 

    private Rectangle bounds; 

    public RectangleDrawable(int x, int y, int width, int height, Color strokeColor, Color fillColor) { 
     super(strokeColor, fillColor); 
     bounds = new Rectangle(x, y, width, height); 
    } 

    @Override 
    public Rectangle getBounds() { 
     return bounds; 
    } 

    @Override 
    public void paint(Graphics2D g2d) { 
     g2d.setColor(getFillColor()); 
     g2d.fill(getBounds()); 
     g2d.setColor(getStrokeColor()); 
     g2d.draw(getBounds()); 
    } 

} 

public class OvalDrawable extends AbstractDrawable { 

    private Ellipse2D bounds; 

    public OvalDrawable(int x, int y, int width, int height, Color strokeColor, Color fillColor) { 
     super(strokeColor, fillColor); 
     bounds = new Ellipse2D.Double(x, y, width, height); 
    } 

    @Override 
    public Rectangle getBounds() { 
     return bounds.getBounds(); 
    } 

    @Override 
    public void paint(Graphics2D g2d) { 
     g2d.setColor(getFillColor()); 
     g2d.fill(bounds); 
     g2d.setColor(getStrokeColor()); 
     g2d.draw(bounds); 
    } 

} 

Ich würde dann eine spezielle Komponente haben, die sie für die Verwaltung und Malerei

Simple Shapes

public class DrawablePane extends JPanel { 

    private List<Drawable> drawables; 

    public DrawablePane() { 
     drawables = new ArrayList<>(25); 
    } 

    public void add(Drawable drawable) { 
     drawables.add(drawable); 
     repaint(); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(200, 200); 
    } 

    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2d = (Graphics2D) g.create(); 
     for (Drawable drawable : drawables) { 
      drawable.paint(g2d); 
     } 
     g2d.dispose(); 
    } 

} 

, die verwendet werden könnte so etwas wie ...

EventQueue.invokeLater(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
      ex.printStackTrace(); 
     } 

     DrawablePane pane = new DrawablePane(); 
     pane.add(new RectangleDrawable(10, 10, 100, 150, Color.YELLOW, Color.GREEN)); 
     pane.add(new OvalDrawable(100, 20, 50, 50, Color.MAGENTA, Color.BLUE)); 

     JFrame frame = new JFrame("Testing"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(pane); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 
}); 
+0

Kann jemand die down vote erklären? Beantwortet die Antwort die Frage des Nutzers nicht? Tut es etwas falsch? Ich wäre daran interessiert zu erfahren, wie es verbessert werden könnte – MadProgrammer

1

Ihr größtes Problem besteht darin, dass Sie alle Dimensionen (x, y, width, height) in ShapeDef überschreiben und nicht die JCompoment-Methoden (setSize, setPreferredSize(), setLocation) verwenden, um sie festzulegen. Daher haben Ihre ShapeDefs keine Größe und jedes Mal, das Sie in ihnen machen, wird durch den Grafikausschnitt blockiert.

Sie sollten auch explizit die Layout-Manager Ihres Panel gesetzt

+0

Und es gibt keinen Grund, pan.revalidate() und pan.repaint() im Window-Konstruktor aufzurufen. Sollte pack pack() vor setVisible (true) aufrufen. – FredK

+0

Ich habe einen juckenden Finger, um Ihnen eine -1 für die 'Null'-Layout-Vorschlag zu geben – MadProgrammer

+0

@MadProgrammer Ich weiß, wo Sie herkommen. Wenn dies für eine Geschäftslösung wäre, würde ich kein Null-Layout empfehlen. Aber da der Code OP veröffentlicht/bereits entwickelt wurde, scheint es zu schwierig zu sein, getPreferredSize zu umgehen oder setPreferredSize zu verwenden. – ControlAltDel

1

Hinzugefügt Artikel zu JPanel nicht auf null‘zeigen

Wenn Sie JComponent erstreckt, JComponent sich bereits Eigenschaften seiner hat Regierungs Dimension und Ort wie x, y, width, height.

Anstatt jedoch die geerbten Eigenschaften zu verwenden, erstellen Sie eine weitere Gruppe von Eigenschaften mit denselben Namen, die die übernommenen Attribute überschatten können.

Ich sehe, dass Sie Ihre eigenen erstellen x, y, width, height die nicht notwendig ist. Wenn diese für andere Zwecke erstellt werden, möchten Sie sie möglicherweise in etwas anderes umbenennen.


Other than that, wenn Sie nur einige benutzerdefinierte Zeichnung haben wollen, müssen Sie nicht immer Ihre ShapeDef Klasse zu einem JComponent zu erstreckt. Sie können dies tun:

class ShapeDef 
{ 
    //other constructors and attributes not shown 
    public void draw(Graphics g){ 
     //draw your drawings here.. 
    } 
} 

Lassen Sie Ihre JPanel eine Instanz von ShapeDef halten, und es in der JPanel zu ziehen, tun Sie es einfach wie:

public MyPanel extends JPanel 
{ 
    ShapeDef shapeDef; 

    //initializations and constructors not shown 

    @Override 
    public void paintComponent(Graphics g){ 
     shapeDef.draw(g);   
    } 
} 
1

Zusätzlich zu dem, was die ControlAltDel in his Answer (Wenn Sie LayoutManager auf null setzen, müssen Sie die x- und y-Koordinaten für fillRect und fillOval auf Null setzen. Wenn Sie dies nicht tun, ist das Rechteck wegen Übersteuerung nicht sichtbar.

public class ShapeDef extends JComponent { 
    private final Color color; 
    private int width, height; 
    private final String type; 

    public ShapeDef(String type, Color color, int x, int y, int width, int height){ 
     this.type = type; 
     this.color = color; 
     this.width = width; 
     this.height = height; 
     this.setBounds(x, y, width, height); // creates a bounding box for your drawing 
    } 

    @Override 
    protected void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     if(type.equalsIgnoreCase("Rectangle")){ 
      g.setColor(color); 
      g.fillRect(0, 0, width, height); // draws inside of your bounding box 
      System.out.println("Rect"); 
     } 
     else if(type.equalsIgnoreCase("Oval")){ 
      g.setColor(color); 
      g.fillOval(0, 0, width, height); // draws inside of your bounding box 
     } 
    } 
} 

Verwenden Sie auch eine Enum statt Strings für den Typparameter.

0

Ihre Klasse ShapeDef sollte ihre Größe und Position haben. Man könnte es definieren, wie folgend:

public class ShapeDef extends JComponent { 
    private final Color color; 
    private final String type; 

    public ShapeDef(String type, Color color, int x, int y, int width, int height) { 
     this.type = type; 
     this.color = color; 

     setPreferredSize(new Dimension(width, height)); 
     setLocation(new Point(x, y)); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (type.equalsIgnoreCase("Rectangle")) { 
      g.setColor(color); 
      g.fillRect(getX(), getY(), getSize().width, getSize().height); 
      System.out.println("Rect"); 
     } else if (type.equalsIgnoreCase("Oval")) { 
      g.setColor(color); 
      g.fillOval(getX(), getY(), getSize().width, getSize().height); 
     } 
    } 
} 

Dann können Sie es in Ihrem Fenster Klasse wie folgt verwenden:

public class MyWindow extends JFrame { 
    private JPanel myPanel; 
    private ShapeDef shape; 

    public MyWindow() { 
     super("Test Window"); 
     setLayout(new BorderLayout()); 

     myPanel = new JPanel(new BorderLayout()); 
     myPanel.setBackground(Color.BLACK); 

     shape = new ShapeDef("Rectangle", Color.green, 200, 300, 20, 80); 
     myPanel.add(shape, BorderLayout.CENTER); 

     add(myPanel, BorderLayout.CENTER); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 


    public static void main(String args[]) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame myFrame = new MyWindow(); 
       myFrame.pack(); 
       myFrame.setVisible(true); 
      } 
     }); 
    } 
} 

Sie wirklich nicht brauchen, die angepasst Panel Klasse in Bezug auf was Sie mit ihm tun .

+0

Ich habe Ihre Version versucht (Ignorieren des Panels) Klasse) aber Problem hier ist, dass das Rechteck mit dem Fenster skaliert, so dass es nicht die eingestellte Größe ist, es ist immer die gleiche Größe wie das Fenster – Name55555555

+0

@ Name55555555 Ich dachte, das ist, was Ihr ursprünglicher Code versucht, weil Sie wollen, dass die Form zu sein Komponente. Wenn dein Code funktioniert hätte, hätte es auch so funktioniert. Um Ihre Anforderung zu erfüllen, müssen Sie Ihre Form in einem Panel mit der gleichen Größe hinzufügen und dieses Panel zu Ihrem Frame hinzufügen, während Ihr Frame kein BorderLayout verwendet. FlowLayout behält die Größe des Panels bei. Oder Sie können ein GridBagLayout zum Layout Ihrer Komponenten verwenden. –

Verwandte Themen