getGraphics() vermeiden

Java xyrse123

Bekanntes Mitglied
Hallo,
wenn man auf das Fenster klickt, soll an der Stelle ein Quadrat gezeichnet werden, bisher habe ich das mit getGraphics() gelöst. Jetzt habe ich gelesen das man getGraphics vermeiden soll und versucht es abzuändern.
Java:
public class Animation extends JPanel {   
    JPanel Animation = new JPanel();           
   
    Animation() {
            setPreferredSize(new Dimension(300,300));
            setBackground(Color.YELLOW);
            addMouseListener( new MausEreignisse());       
    }
       
    class MausEreignisse extends MouseAdapter {                   
        @Override
            public void mousePressed(MouseEvent e) {              
            Quadrat q = new Quadrat( e.getX(), e.getY());     //Koordinaten bekommen                     
            }
        }      
 
   class Quadrat   {     // Quadrat was gezeichnet werden soll                           
            
            int intX, intY;
            Graphics g=getGraphics();               
       
            public Quadrat(int intX, int intY) {                                                         
             g.fillRect(intX, intY, 20, 20);
            }  
}
               
    public static void main(String[] args) {
           
        JFrame f = new JFrame();
        f.setSize(300,300);
        f.add(new Animation());
        f.setVisible(true);       
    }   
}


Ich hatte dann so etwas probiert:
Java:
class Quadrat  extends JPanel  {                                
            int intX, intY;                                   
           
            public Quadrat(int intX, int intY) {                                                                 
                this.intX=intX; this.intY=intY;                                                                               
            }           
           
        @Override   public void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.RED);
                g.fillRect(intX, intY, 20,20);        
            }
    }
Dann werden aber keine Quadrate gesetzt. Könnte mir wer einen Tipp geben woran das liegt?
Schonmal danke im Vorraus.
 

Meniskusschaden

Top Contributor
In der zweiten Version erweitert Quadrat JPanel. Du erzeugst zwar ein Quadrat-Objekt, machst aber nichts damit. Warum sollte das also angezeigt werden? Wenn es angezeigt werden soll, muss es auch dem Animations-Panel hinzugefügt werden. Du musst aber bedenken, dass deine Methode paintComponent() nicht zum Animations-Panel gehört, sondern zum Quadrat-Panel.
Du kannst auch näher an deinem ursprünglichen Ansatz bleiben und das Quadrat einfach in der Methode paintComponent() des Animations-Panel zeichnen. Dann muss Quadrat JPanel nicht erweitern
 

Damtonix

Mitglied
Ich habe eine Lösung für dein Problem gefunden. Die Quadrate sind jetzt in einem 2D-Array abgespeichert. Das hat den Vorteil, dass man jedes einzelne Quadrat im Nachhinein wenn man will ansteuern kann. Jetzt ist es aber so, wenn man das Fenster vergrößert, ist das Array zu klein und man müsste die Größe anpassen. Das habe ich jetzt nicht reingeschrieben, denn ich weiß nicht in wie fern du das einbauen willst. Also, viel Erfolg!

Java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Animation extends JPanel {  
   
    JPanel Animation = new JPanel();  
    int qWidth = 20, qHeight = 20;
    boolean[][] quadrat = new boolean[300][300];
  
    Animation() {
            setPreferredSize(new Dimension(qWidth, qHeight));
            setBackground(Color.YELLOW);
            addMouseListener( new MausEreignisse());      
    }
      
    protected class MausEreignisse extends MouseAdapter {                  
        @Override
        public void mousePressed(MouseEvent e) {             
            quadrat[e.getX()][e.getY()] = true;     //Koordinaten bekommen    
            repaint();
        }
    }     
    public void paint(Graphics g) {
        super.paint(g);
        for(int a = 0; a < getWidth(); a++) {
            for(int b = 0; b < getHeight(); b++) {
                if(quadrat[a][b]) {
                    g.fillRect(a, b, qWidth, qHeight);
                }
            }
        }
    }
              
    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setSize(300,300);
        f.add(new Animation());
        f.setVisible(true);      
    }  
}
 

Damtonix

Mitglied
Ich habe noch eine einfachere Variante gefunden, das Problem zu lösen. Vielleicht gefällt sie dir besser:
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Animation {  
   
    protected static JFrame f = new JFrame();     //Fenster
   
    public static void main(String[] args) {
       
        f.setSize(300,300); //Größe festlegen
        f.addMouseListener(new MausEreignisse()); //MouseListener hinzufügen
        f.setVisible(true); //Fenster Sichtbar machen
       
        JPanel p = new JPanel(); //JPanel wird erstellt
        p.setBackground(Color.YELLOW); //Hintergrund: GELB
       
        f.setContentPane(p); //Das JPanel wird als ContentPane verwendet
    }
   
    protected static class Quadrat extends JLabel {
       
        public Quadrat(int x, int y) {
            setBounds(x - 16/*Die Abzüge sorgen dafür, dass das Quadrat mittig ist :)*/, y - 38/*ebenso*/, 20, 20); //Position und Größe festlegen (Quadrat)
        }
       
        public void paint(Graphics g) {
            super.paint(g);
            g.fillRect(0, 0, 20, 20); //Rechteck zeichnen
        }
    }
   
    protected static class MausEreignisse extends MouseAdapter {
       
        public void mousePressed(MouseEvent e) {             
            f.getContentPane().add(new Quadrat(e.getX(), e.getY())); //Quadrat erstellen
            f.getContentPane().repaint(); //Neu zeichnen
        }
    }
}
 

Java xyrse123

Bekanntes Mitglied
Die Animationsklasse erbt jetzt nicht mehr von JPanel und Paint() wird in der Quadrat Klasse aufgerufen.
Warum funktioniert folgendes nicht?
Java:
@Override
            public void mousePressed(MouseEvent e) {            
            Quadrat r = new Quadrat( e.getX(), e.getY());                        
            Animation.add(r);          // Hinzufügen
        }

I
Du kannst auch näher an deinem ursprünglichen Ansatz bleiben und das Quadrat einfach in der Methode paintComponent() des Animations-Panel zeichnen. Dann muss Quadrat JPanel nicht erweitern

Dann wird das Quadrat doch immer gezeichnet und nicht nur bei einem Mausklick, oder?
 

Meniskusschaden

Top Contributor
Die Animationsklasse erbt jetzt nicht mehr von JPanel
Schade. Das war eigentlich ganz vernünftig. Dann stellt sich natürlich die Frage, was die Methode add() jetzt eigentlich macht. Die kann jetzt ja nicht mehr vom Panel geerbt sein.
und Paint() wird in der Quadrat Klasse aufgerufen.
Man sollte paint() nicht aufrufen. Das macht Swing selbständig. Wenn man etwas programmiert hat, das ein Neuzeichnen erforderlich macht, sollte man repaint() aufrufen.
Dann wird das Quadrat doch immer gezeichnet und nicht nur bei einem Mausklick, oder?
Es wird das gezeichnet, was man in paintComponent() programmiert hat. Dort muss man also wissen, was gezeichnet werden soll. Ich vermute mal, dass dein Quadrat auch dann noch angezeigt werden soll, wenn du die Maustaste wieder losgelassen hast. Du musst also bei den Mausklicks deine Objekte erzeugen, sie in einer geeigneten Datenstruktur speichern und repaint() aufrufen. In paintComponent() zeichnest du diese Objekte dann.
Alternativ - je nachdem, was du erreichen willst - kannst du dein Quadrat auch JPanel erweitern lassen und es deinem (ursprünglichen) Animations-Objekt hinzufügen. Je nachdem wie dein Quadrat aussehen soll, brauchst du dann unter Umständen keine eigene paintComponent() Methode.
Im Moment ist unklar, welchem Ansatz du gerade folgst und demzufolge kann man da auch nicht richtig konkret werden.
 

Java xyrse123

Bekanntes Mitglied
Sorry ich habe es missverständlich beschrieben:

Schade. Das war eigentlich ganz vernünftig. Dann stellt sich natürlich die Frage, was die Methode add() jetzt eigentlich macht. Die kann jetzt ja nicht mehr vom Panel geerbt sein.

Java:
    JPanel Animation=new JPanel();     
    JPanel Quadrat = new JPanel();
   
    HelloWorld() {
            Animation.setPreferredSize(new Dimension(300,300));
            Animation.setBackground(Color.YELLOW);
            Animation.addMouseListener( new MausEreignisse());         
    }

Man sollte paint() nicht aufrufen. Das macht Swing selbständig. Wenn man etwas programmiert hat, das ein Neuzeichnen erforderlich macht, sollte man repaint() aufrufen.
Ich meinte das ich in der Quadrat Klasse zeichne.[/QUOTE]
 

Java xyrse123

Bekanntes Mitglied
Ok, dann poste ich nochmal das Programm, wie ich es verändert habe.
in Post #8 war auch noch ein Fehler, ich meinte Animation statt "HelloWorld" habe da irgendwie was falsch reinkopiert...
Java:
public class Animation {
 
    static JPanel Animation=new JPanel(); 
    JPanel Quadrat = new JPanel();
 
    Animation() {
            Animation.setPreferredSize(new Dimension(300,300));
            Animation.setBackground(Color.YELLOW);
            Animation.addMouseListener( new MausEreignisse());     
    }
 
    class MausEreignisse extends MouseAdapter {
             
        @Override
            public void mousePressed(MouseEvent e) {         
            Quadrat q= new Quadrat( e.getX(), e.getY());                   
            Animation.add(q); // Warum wird hier das Quadrat nicht hinzugefügt?
            Animation.repaint();
         }
        }
 
 
    class Quadrat  extends JPanel  {                       
            int intX, intY;                             
     
            public Quadrat(int intX, int intY) {                                                           
                this.intX=intX; this.intY=intY;                                                                         
         
            }     
            @Override   public void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.RED);
                g.fillRect(intX, intY, 20,20); 
            }
 
    }
         
    public static void main(String[] args) {
     
        JFrame f = new JFrame();
        f.setSize(300,300);
        f.setLayout(new FlowLayout());
        f.add(Animation,new Animation());
        f.setVisible(true);
 
    }
}
 
Zuletzt bearbeitet:

Meniskusschaden

Top Contributor
Da sind noch jede Menge Fehler und das Programm ist insgesamt völlig undurchsichtig. So gibt es eine Klasse Animation und ein gleichnamiges JPanel, was sehr verwirrend ist. Die Initialisierung des Panel-Objekts Animation erfolgt im Konstruktor des Animations-Objektes (welches ja nicht das Animations-Panel ist). Das Animations-Objekt wird skurrilerweise dem LayoutManager als Constraint übergeben. Das Mischmasch von statischen und Instanzvariablen macht das ganze nicht übersichtlicher.

Der Name Quadrat ist ebenfalls doppelt vergeben. Einmal als Klassenname und einmal als Instanzvariable, welche aber überhaupt nicht verwendet wird.

Du solltest das unbedingt aufräumen oder noch einmal mit einem neuen Projekt sauber beginnen.

Ein anderes Problem ist das Zeichnen des Quadrats. Du machst das in der paintComponent-Methode des Quadrats verwendest aber die Koordinaten des Mausklicks im Animations-Panel. Es stellt sich die Frage, ob es überhaupt sinnvoll ist, das Quadrat selbst zu zeichnen, wenn es ohnehin ein eigenes Panel wird. Du könnest ja auch einfach dessen Farbe setzen, wie du es mit dem Animationspanel auch gemacht hast.

Außerdem ist unklar, wie deine Quadrate positioniert werden sollen. Sollen die jetzt an der Mausposition erscheinen oder per LayoutManager platziert werden? Unterm Strich würde das Quadrat-Panel momentan wohl nicht dort erscheinen, wo du es haben willst und das Quadrat würde innerhalb des Quadrat-Panels auch nicht dort gezeichnet werden, wo du es haben willst.

Da du kein repaint() aufrufst wirst du davon aber erst etwas sehen, wenn du beispielsweise mit der Maus das Fenster vergrößerst um dadurch ein repaint auszulösen.

Ich glaube, es ist einfacher, das Projekt noch einmal neu aufzusetzen, als das vorhandene zu verbessern. Vorher würde ich mir aber überlegen, welchen Ansatz du verfolgen willst: Nur ein Animationspanel, in dem du alle Quadrate selbst zeichnest oder ein Panel pro Quadrat, das du dann aber nicht selbst zeichnest. Im Moment ist auch das noch vermischt.
 

Java xyrse123

Bekanntes Mitglied
Es funktioniert jetzt, ich habe mich dabei ein bisschen an Damtonix Lösung gehalten. Jetzt wollte ich das sich bei einem Klick das Quadrat dann auch nach rechts bewegt, also das jedesmal ein neuer Thread erzeugt wird.
Der Thread startet und jedes neue Quadrat "zieht sich zusammen und verschwindet"(ich weiß nicht wie ich es besser beschreiben kann), weil intX(also die obere linke Koordinate) in der Quadratklasse null ist.
Wie bekomme ich dann die aktuelle x Koordinate von dem Rechteck?
Java:
class Quadrat extends JLabel implements Runnable {
...
@Override
        public void run() {
              
            while(!Thread.currentThread().isInterrupted()) {
            intX=intX+4;          
            repaint();
            try {
                Thread.sleep(100);
            } catch(Exception e) {}
            }              
        }      
}

class MausEreignisse extends MouseAdapter {                     
        
 public void mousePressed(MouseEvent e) {                   
            Quadrat q = new Quadrat(e.getX(), e.getY());
            p.add(q);        
            Thread t = new Thread(q);              
            t.start();             
        }
    }
 

Java xyrse123

Bekanntes Mitglied
Darauf:
Java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Animation { 
   
   JFrame f = new JFrame();   
   JPanel p =new JPanel();

   Animation() {
        f.setSize(300,300); 
        f.addMouseListener(new MausEreignisse()); 
        f.setVisible(true);     
        p.setBackground(Color.YELLOW); 
        f.add(p);
    }
     
    public static void main(String[] args) {       
        new Animation();
    }
   
    class Quadrat extends JLabel implements Runnable {
      int intX, intY;
     
      public Quadrat(int intX,int intY) {
          setBounds(intX-16, intY-38, 20,20);     
      }
       
        public void paint(Graphics g) {
            super.paint(g);
            g.fillRect(intX, intY, 20, 20); //Rechteck zeichnen
        }
             
        @Override
        public void run() {
               
            while(!Thread.currentThread().isInterrupted()) {
            intX=intX+4;            // Bewegung nch rechts           
            repaint();
            try {
                Thread.sleep(100);
            } catch(Exception e) {}
            }               
        }
    }
    class MausEreignisse extends MouseAdapter {                      
          public void mousePressed(MouseEvent e) {             
         
            Quadrat q = new Quadrat(e.getX(), e.getY());
            p.add(q);                                         
           
            Thread t = new Thread(q);               
            t.start();               
        }
    }
}
 

Meniskusschaden

Top Contributor
Der Thread startet und jedes neue Quadrat "zieht sich zusammen und verschwindet"(ich weiß nicht wie ich es besser beschreiben kann), weil intX(also die obere linke Koordinate) in der Quadratklasse null ist.
Du zeichnest zunächst ein 20x20 großes Rechteck an der Position (0, 0) auf ein 20x20 großes JLabel. Das passt also genau da rein. Danach erhöhst du x sukzessive in Vierer-Schritten und zeichnest das Rechteck an den Positionen (4,0), (8,0), ... auf das JLabel, das aber nur 20 Pixel breit ist. Das Rechteck passt also zunächst nur teilweise und später gar nicht mehr da rein.
Wie bekomme ich dann die aktuelle x Koordinate von dem Rechteck?
Vom Rechteck oder vom JLabel?
Das Label könntest du z.B. so bewegen: setLocation(getX()+4, getY());. Du solltest aber auch nicht mehr das Rechteck im Label verschieben, denn das bleibt ja trotzdem nur 20 Pixel breit.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Q getGraphics() - NullPointerException AWT, Swing, JavaFX & SWT 8
P Swing Frage zu paintComponent/getGraphics AWT, Swing, JavaFX & SWT 4
hdi Swing Frage zu getGraphics() AWT, Swing, JavaFX & SWT 7
I getGraphics().setColor funktioniert nicht AWT, Swing, JavaFX & SWT 6
Kr0e Transparentes Image -> getGraphics AWT, Swing, JavaFX & SWT 8
C getGraphics() liefert nur null AWT, Swing, JavaFX & SWT 4
H wie, wenn nicht mit getGraphics ? AWT, Swing, JavaFX & SWT 10
H getGraphics() eines JPanel liefert immer null zurück AWT, Swing, JavaFX & SWT 6
B JPanel -> getGraphics() AWT, Swing, JavaFX & SWT 2
Neumi5694 internal property vermeiden AWT, Swing, JavaFX & SWT 0
N Swing Duplikate im Jcombobox vermeiden AWT, Swing, JavaFX & SWT 15
M Zeichenketten in GUIs (toString() vermeiden?) AWT, Swing, JavaFX & SWT 4
P 2D-Grafik Werteanpassung des DefaultCategoryDatasets vermeiden AWT, Swing, JavaFX & SWT 4
Luk10 Vermeiden von CurrentModificationException AWT, Swing, JavaFX & SWT 10
2 Doppelt zeichnen vermeiden? AWT, Swing, JavaFX & SWT 22
R JTextPane scrollen vermeiden AWT, Swing, JavaFX & SWT 2
T Doppelte Abfrage eine Checkbox vermeiden AWT, Swing, JavaFX & SWT 2
T JScrollPane - Scrollbalken vermeiden AWT, Swing, JavaFX & SWT 5
C Permanenter Inhalt für JPanel (repaint vermeiden) AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben