# Komponenten verschwinden von JPanel, wenn ich den HG selbst male - Hilfeeee



## data89 (3. Nov 2009)

Hallo Leute,

ich habe eine einfache Klasse, die von JPanel abgeleitet ist. In dieser Klasse überschreibe ich die Methode "public void paint(Graphics g)" vom JPanel. Alles klappt wunderbar, bis man etwas mit dem Fenster macht.* Sobald ich das Fenster verschiebe/verkleinere/vergrößere wird nur noch das JPanel gezeichnet und nicht mehr die Komponenten auf dem JPanel. Was mache ich da falsch? Wie kann ich dafür sorgen, dass dies nicht passiert?*


```
public void paint(Graphics g) {
        super.paint(g);

        Graphics2D g2d = (Graphics2D)g;
        // male was ...
}
```


----------



## Verjigorm (3. Nov 2009)

paintComponent() überschreiben, nicht paint()!

http://www.java-forum.org/awt-swing-swt/43939-zeichnen-swing-tutorial.html


----------



## data89 (3. Nov 2009)

Vielen Dank, hab es gerade herausgefunden durch learning by doing!

Aber noch eine Frage: das mit dem selbstzeichen klappt ja jetzt wunderbar. Aber, wenn ich ein PopUp-Menü (durch Rechtsklick) öffne und eine Option auswähle, dann *schließt sich das PopUp-Menü und zurück bleibt ein grauer Kasten im Bild. Da das ganz und garnicht schön ist, frage ich Euch, ob Ihr wisst, wie man diesen Kasten entfernt?*

Mein erster Ansatzpunkt war, immer einen repaint() des Fensters aufzurufen, wenn eine Option im PopUp-Menü gewählt wurde, aber das ist ja wohl nicht der Sinn des ganzen ... da gibt's doch sicher noch eine elegantere Variante, oder?

Danke, 
data89

P.S.: Und noch ein Problem hab ich: bei den Rundungen von den Buttons (z.B. XP-LaF) wird immer ein weißer Rand gezeichnet. Aber ich denke, dass ich das mit Hilfe dieser Seite in den Griff bekomme: Java tip: Use gradient backgrounds to add interest and polish to a user interface | Nadeau Software


----------



## Nicer (3. Nov 2009)

Der Repaint wäre sicherlich eine lösung , unschön aber würde glaubich gehn , ansonsten einfach popupmenu in dem zeichenfeld sperren und nur ausserhalb des feldes zugänglich machen.


----------



## Gast2 (3. Nov 2009)

wie setzt und öffnest du dein Popupmenu??


----------



## data89 (3. Nov 2009)

Nicer hat gesagt.:


> Der Repaint wäre sicherlich eine lösung , unschön aber würde glaubich gehn , ansonsten einfach popupmenu in dem zeichenfeld sperren und nur ausserhalb des feldes zugänglich machen.


"zeichenfeld sperren" - was bedeutet das? Etwa, dass ich die Methode "protected" nenne?



SirWayne hat gesagt.:


> wie setzt und öffnest du dein Popupmenu??


Hier nochmals zum anschauen:





Das oberste - da ist alles okay. Darunter sieht man die Fehler in den rot eingekreisten Bereichen und teile davon verschwinden auch nicht mit einem repaint() ...

Die von JPanel abgeleitete Klasse hat folgende Methoden:

```
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    // paint s.th. here 
}
```

Erzeugung des Pop-Up-Menüs:

```
JButton btn = new JButton("Btn");
		
                final JButton btnObj = btn;
                final JPopupMenu pop = new JPopUpMenu();
		btn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				pop.show(btnObj , 0, btnObj.getPreferredSize().height);
			}
		});
		
                // add s.th. to the pop up menu
                pop.add(new JMenuItem("Item 1"));
```

Danke vorab!


----------



## Gast2 (3. Nov 2009)

Mach mal ein KSKB...

Und was soll den das hier?

```
JButton btn = new JButton("Btn");
        
                final JButton btnObj = btn;
```


----------



## data89 (4. Nov 2009)

Ich muss ja in "actionPerformed" den Button zur Verfügung haben. Und da die ActionListener-Klasse "eingebaut" ist, kann man so am einfachsten darauf zugreifen ...


----------



## Gast2 (4. Nov 2009)

Es gibt auch 
	
	
	
	





```
e.getSource();
```

wie gesagt zu deinem anderen Problem mach mach ein KSKB


----------



## data89 (4. Nov 2009)

Wenn man in Zeile 16 die "0" durch z.B. "100" ersetzt, dann ist der Effekt noch größer.




Hier ein Beispiel, das beim Klick auf den Button den Effekt zeigt (oberer Teil im Bild):

```
public class GUI extends JFrame {

	private JPopupMenu pop;

	public GUI() {
		this.setLayout(new BorderLayout());
		
		JPanel p = new TestPanel();
		
		JButton btn = new JButton("Action");
		
       	this.pop = new JPopupMenu();
		btn.addActionListener(new ActionListener() {
		    public void actionPerformed(ActionEvent a) {
		    	JButton btn = (JButton) a.getSource();
		        pop.show(btn, 0, btn.getPreferredSize().height);
		    }
		});

        // add s.th. to the pop up menu
		pop.add(new JMenuItem("Item 1"));
		pop.add(new JMenuItem("Item 2"));
		pop.add(new JMenuItem("Item 3"));
		pop.add(new JMenuItem("Item 4"));
		
		p.add(btn);
		this.add(p, BorderLayout.PAGE_START);
		
		this.pack();
		this.setSize(new Dimension(900, 600));
	}
	
	class TestPanel extends JPanel {
		
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			
			int width = g.getClipBounds().width;
			int height = g.getClipBounds().height;
	        Graphics2D g2d = (Graphics2D)g;
	        g2d.fillRect(0, 0, width, height);
		}
		
	}
	
	public static void main(String[] args) {
		new GUI().setVisible(true);
	}
	
}
```


----------



## Gast2 (4. Nov 2009)

```
pop.addPopupMenuListener(new PopupMenuListener() {
			
			@Override
			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
				System.out.println("popupMenuWillBecomeVisible");
				
			}
			
			@Override
			public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
				p.repaint();
				
			}
			
			@Override
			public void popupMenuCanceled(PopupMenuEvent e) {
				System.out.println("popupMenuCanceled");
				
			}
		});
```


----------



## data89 (4. Nov 2009)

Es funktioniert, wenn man in "popupMenuWillBecomeVisible" und "popupMenuCanceled" ein repaint setzt!!

Noch eine Frage (ist die letzte!): Wenn ich einen gerundeten Button auf das Panel setze wird ein Rand gezeichnet, der sich nicht durch "setOpaque" beeinflussen lässt - muss ich da auch sowas anwedenen, wie für das Pop-Up-Menü.

EDIT: Das tut's nicht so, wie das letzte Problem zu lösen ...


----------



## Gast2 (4. Nov 2009)

Warum willst du ein PopUp eigentlich mit einem Button öffnen??


----------



## data89 (4. Nov 2009)

SirWayne hat gesagt.:


> Warum willst du ein PopUp eigentlich mit einem Button öffnen??


Weil ich ein Menü machen will, dass nicht so wie jedes aussehen soll, sondern wie diese hier: Vista Web Buttons: Superior html buttons and html menus!


----------



## Gast2 (5. Nov 2009)

Und was hast das jetzt mit dem Button zu tun???
du kannst das Menü nämlich auch mit setComponentPopMenu oder so auf die JComponente adden dann geht es so auf die es bei dem jeweiligen OS ist...


----------



## André Uhres (6. Nov 2009)

Die Lösung mit dem Listener ist schlicht Unfug. Der Fehler liegt bei der Verwendung der ClipBounds. Versuch's mal so:

```
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Rectangle r = g.getClipBounds();
    g.fillRect(r.x, r.y, r.width, r.height);
}
```
Beispiel für einen runden Button:

```
...
        JButton btn = new OvalButton("Action");
        this.pop = new JPopupMenu();
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent a) {
                JButton btn = (JButton) a.getSource();
                pop.show(btn, 0, btn.getHeight());
            }
        });
...
class OvalButton extends JButton {
    public OvalButton(String text) {
        super(text);
        setContentAreaFilled(false);
        setBorderPainted(false);
        setFocusPainted(false);
        setIcon(new OvalIcon());
        setRolloverIcon(new RolloverIcon());
        setPressedIcon(new PressedIcon());
        setHorizontalTextPosition(SwingConstants.CENTER);
        setVerticalTextPosition(SwingConstants.CENTER);
    }
    class OvalIcon implements Icon {
        public void paintIcon(Component c, Graphics g, int x, int y) {
            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setColor(getBackground());
            g.fillOval(0, 0, getIconWidth(), getIconHeight());
        }
        public int getIconWidth() {
            return getWidth();
        }
        public int getIconHeight() {
            return getHeight();
        }
    }
    class RolloverIcon extends OvalIcon {
        @Override
        public void paintIcon(Component c, Graphics g, int x, int y) {
            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setColor(getBackground().darker());
            g.fillOval(0, 0, getIconWidth(), getIconHeight());
        }
    }
    class PressedIcon extends OvalIcon {
        @Override
        public void paintIcon(Component c, Graphics g, int x, int y) {
            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setColor(getBackground().darker().darker());
            g.fillOval(0, 0, getIconWidth(), getIconHeight());
        }
    }
}
```


----------



## data89 (6. Nov 2009)

Danke! Es lag wirklich daran, dass ich nicht die x und y-Koordinate genommen habe! 

Aber es hat sich ein neues Problem ergeben: da ja um den Button herum ja nur das Panel neu geziechnet wird und nicht das ganze Panel, habe ich ein Problem, denn ich arbeite ja mit Farbverläufen:




Daher passt das dann nicht mehr, wenn nur ein Ausschnitt gezeichnet werden soll ... Was kann ich denn nun machen?

EDIT:
Wie ist es, wenn man folgendermaßen vorgeht:

```
public void paintComponent(Graphics g) {
		super.paintComponent(g);
		int width = this.getSize().width;
		int height = this.getSize().height;
                Graphics2D g2d = (Graphics2D)g;
                // hier kann ich alles (mit width/height) neu zeichnen und nur der Ausschnitt wird angezeigt
                // getestet: scheint zu funktionieren
       }
```


----------

