Nachträglich neue grafische Objekte hinzufügen

Carcharoth

Bekanntes Mitglied
Guten Abend

Ich habe eine Klasse Draw welche von JPanel erbt.
Darin zeichne ich etwas in dem ich die Methode paintComponent überschreibe.

Ich möchte später im Programm, durch verschiedene Umstände ausgelöst (z.B. einen Mausklick), weitere grafische Elemente (Rechtecke, Kreise, Linien, usw.) einfügen können. Mein Problem ist dabei, dass ich alles was ich zeichne in der Methode paintComponent einbauen muss. Ich weiss aber nicht von Anfang an, was später alles gezeichnet werden muss.

Java:
public class Draw extends JPanel {
    public Draw() {
        setBounds(0,0,800,600);
        Handler handler = new Handler();
        this.addMouseListener(handler);
    }
    
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.RED);
        g.fillOval(300, 300, 200, 100);
        repaint();
    }
    
    private class Handler implements MouseListener {
        @Override
        public void mouseClicked(MouseEvent e) {
            // neues grafische Element hinzufügen (Rechteck, Kreis, Linie, usw.)
        }

        @Override
        public void mouseEntered(MouseEvent arg0) {}

        @Override
        public void mouseExited(MouseEvent arg0) {}

        @Override
        public void mousePressed(MouseEvent arg0) {}

        @Override
        public void mouseReleased(MouseEvent arg0) {}
    }
}

Ich habe mir überlegt, dass ich eine innere Klasse Element (extends JPanel) bauen könnte die die Aufgabe hat jedes neues grafische Element zu beherbergen.
Mit Aufruf ihrer repaint-Methode könnte ich es zeichnen lassen.

Könnte dieser Ansatz funktionieren?

Nun tue ich mich schwer dem Konstruktor von Element ein gescheiter Parameter zu übergeben damit Element weiss was es ist (z.B. ein Rechteck, ein Kreis, eine Linie, usw.). Am liebsten würde ich ein Parameter eines übergeordneten Typs (Graphics?) übergeben. Die Klasse Element wüsste dann was zu zeichnen ist.

Kann ich das so generisch machen (man darf ja träumen) oder muss ich für jedes graphisches Element welches ich später hinzufügen will eine eigene Klasse bauen (eine für Rechtecke, eine für Kreise, eine für Linien, usw.)?

Danke und Gruss
 
Auf dem Weg zu der Lösung, versuche ich zuerst eine innere Klasse Element zu bauen und eine Instanz davon im Konstruktor von Draw hinzuzufügen und zeichnen lassen. Klappt aber nicht. Irgendwie kann ich machen was ich will, es kommt immer nur ein kleines blaues Viereck oben mittig gezeichnet.

Danke für eure Tipps.

Java:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

public class Draw extends JPanel {
    // Konstruktor von Draw
    public Draw() {
        setBounds(0,0,800,600);

        Element neuesElement = new Element();
        this.add(neuesElement);
    }

    // überschriebene paintComponent von Draw
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.RED);
        g.fillOval(300, 300, 200, 100);
        repaint();
    }

    private class Element extends JPanel {
        // Konstruktor von Element
        Element() {
            this.setBounds(0,0,800,600);
        }

        // überschriebene paintComponent von Element
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            g.setColor(Color.BLUE);
            g.fillRect(0, 0, 200, 200);
            repaint();
        }
    }
}

Java:
import javax.swing.JFrame;

public class Fenster extends JFrame {

    public Fenster() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800,600);
        setLocationRelativeTo(null);

        Draw draw = new Draw();
        this.add(draw);

        setVisible(true);
    }

    public static void main(String[] args) {
        Fenster meinFenster = new Fenster();
    }
}
 
versuche ich zuerst eine innere Klasse Element zu bauen und eine Instanz davon im Konstruktor von Draw hinzuzufügen und zeichnen lassen
Das Problem ist, dass Element eine Komponente ist. Hier schlägt dann der LayoutManager zu. Wenn ich Dich richtig verstanden habe, willst Du aber keine UI-Komponenten hinzufügen, sondern grafische Objekte, oder?
 
Hier mal was zum Spielen:

Java:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;
import java.util.List; // wg. awt

interface Drawable {
    void paint(Graphics2D g);
}

class DrawableShape implements Drawable {
    private Shape shape;
    private Stroke stroke;
    private Paint fill;

    public DrawableShape(Shape shape, Stroke stroke, Paint fill) {
        this.shape = shape;
        this.stroke = stroke;
        this.fill = fill;
    }

    @Override
    public void paint(Graphics2D g) {
        g.setPaint(fill);
        g.setStroke(stroke);
        if (fill != null) {
            g.fill(shape);
        } else {
            g.draw(shape);
        }
    }
}
    

class DrawingPane extends JComponent {
    private List<Drawable> elements = new LinkedList<>();

    public void add(Drawable element) {
        elements.add(element);
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        
        for (Drawable e : elements) {
            e.paint(g2);
        }
    }    
}

public class Draw {

    private DrawingPane drawings;
   

    public void run() {
        drawings = new DrawingPane();
        drawings.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                addEllipse(e.getPoint());
            }
        });
                
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(drawings);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    private void addEllipse(Point2D p) {
        Ellipse2D ellipse = new Ellipse2D.Double(
                     p.getX() - 25, p.getY() - 25, 50, 50);
        
        Stroke dashed = new BasicStroke(2.0f,
                                        BasicStroke.CAP_BUTT,
                                        BasicStroke.JOIN_MITER,
                                        10.0f, new float[]{10.0f}, 0f);

        DrawableShape drawable = new DrawableShape(ellipse, dashed, null);
        drawings.add(drawable);        
    }    

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Draw().run());
    }
}
 

Zurück
Oben