# Repaint Probleme bei Swing (JScrollPane größe ändern)



## Stefan1200 (6. Okt 2003)

Ich habe ein repaint Problem.
Sobald ich nach einem Resize der JFrame Componente zwei JScrollPane (Mit JList) in der breite verändern möchte, wird die aktuelle Änderung aber nicht gezeichnet.

Ich habe bereits versucht sämtliche Componenten per repaint() und validate() neuzuzeichen, geht aber nicht, es passiert nichts. Auch e.getComponent().repaint() habe ich versucht, kein unterschied.
So sieht meine componentResized Methode aus:


```
public void componentResized(ComponentEvent e)
	{
		Dimension checkSize = new Dimension(this.getSize());

		int width = ((int)checkSize.getWidth() - 30) / 2;

		dbScroller.setPreferredSize(new Dimension(width,330));
		userScroller.setPreferredSize(new Dimension(width,330));
	}
```


Biiiitte helft mir...


----------



## Stefan1200 (6. Nov 2003)

Hat echt keiner eine Idee oder ein Tipp?


----------



## gustav (6. Nov 2003)

Wird die Methode componentResized(..) überhaupt erreicht. Vielleicht hast Du an der falschen Stelle bzw. beim falschen Objekt den Listener (  this.addComponentListener(this); ) registriert ?


----------



## Stefan1200 (6. Nov 2003)

Doch, das funktioniert alles. Nach dem ich das Fenster ein zweites Mal resize, werden mir die Größen der JScrollPane so angezeigt, wie nach dem ersten Resize. Also es scheint definitiv ein repaint problem zu sein. Aber ich bekomme das nicht hin, weder mit repaint, noch mit validate, habe ich an sämtlichen Componenten ausprobiert.


----------



## gustav (6. Nov 2003)

Glaube mich erinnern zu können schon mal ähnliche Probleme gehabt zu haben. Weiss momentan aber leider nicht mehr wo und wie.

Hilft eventuell eine der 3 Methoden

```
updateUI();   // updates the look and feel !!!
  revalidate();   
  doLayout() ;
```
Die sollten zumindest in JScrollPane vorhanden sein....


----------



## schalentier (6. Nov 2003)

solche probleme sind häufig und die meisten versuchen dann mit wüsten methoden aufrufen das irgendwie hinzubiegen. irgendwann klappt es dann und man versucht nicht mehr drüber nachzudenken, wieso nun eigentlich. 

deswegen sind swing guis so lahm...

also normalerweise sollte man keine der genannten methoden direkt aufrufen, außer man weiß wirklich, warum und wozu die da sind, denn änderungen wie größe/inhalt/etc von swing componenten versuchen normalerweise automatisch ein redraw.

in deinem fall solltest du anstatt

```
setPreferredSize(...)
```
es mit 

```
setSize(...) oder
setDimension(...)
```
probieren.

Die PreferredSize ist nämlich die Größe, die der LayoutManager versucht zu setzen, wenn er ein doLayout durchführt. Das bedeutet aber, dass es nicht unbedingt die tatsächliche Größe am Ende sein wird, sondern es sich eben nur um einen Vorschlag handelt.
Mit Size oder Dimension (bin mir grad nich sicher, wie die genau hieß) stellst du die tatsächliche Größe einer componente ein. Allerdings können auch hier Probleme mit dem zugrunde liegenden LayoutManager auftreten.

Probiers mal aus und sag bescheid.

schalentier


----------



## Stefan1200 (10. Nov 2003)

schalentier hat gesagt.:
			
		

> in deinem fall solltest du anstatt
> 
> ```
> setPreferredSize(...)
> ...



Naja, ich habe auch nie behauptet, das ich ein Profie bin, deshalb frage ich ja ;-)

Schade nur, wenn ich setSize mache (setDimension gibt es nicht), macht er leider gar nichts. Die Größe wird bei mir nur mit setPreferredSize geändert.

Ich habe aber herausgefunden, wie es funktioniert.
Wenn ich direkt nach dem setzen von setPreferredSize folgendes mache:
*SwingUtilities.updateComponentTreeUI(this);*
dann haut es wunderbar hin.

Ich weiss nicht, ob es die beste Lösung ist, aber Sie funktioniert auf jedenfall.
Wenn es aber noch eleganter geht, immer her mit den Vorschlägen.


----------



## peppi (10. Nov 2003)

Hi,

ich hatte ein ähnliches Problem und bekam in den Foren 2 Möglichkeiten zur Lösung:

1. Threats
Zwei Threats anlegen, damit Resourcen zum Repaint() frei bleiben.


2. Update Graphic (habs so umgesetzt)


```
this.update(this.getGraphics());
```
--> Einfügen in die Frame-Class z.B. als ChangeEvent o.ä.

Mit diesem einfachen Befehl wird das Frame updated.

Hoffe ich konnte dir helfen.


----------



## Ebenius (18. Nov 2003)

*... und wenn ihr das noch ein kleines bisschen weiter treibt, dann baut ihr nach dem resize die graphik-karte aus und wieder ein und updated dann die treiber auch noch.*

@Stefan1200 Schick mir mal ein bisschen mehr source (oder poste's einfach) dann such ich nen sauberen weg, okay?

Grüße, Ebenius


----------



## Stefan1200 (18. Nov 2003)

Ebenius hat gesagt.:
			
		

> *... und wenn ihr das noch ein kleines bisschen weiter treibt, dann baut ihr nach dem resize die graphik-karte aus und wieder ein und updated dann die treiber auch noch.*
> 
> @Stefan1200 Schick mir mal ein bisschen mehr source (oder poste's einfach) dann such ich nen sauberen weg, okay?



Naja, die Grafikkarte kann drinn bleiben ;-)
Hier mal ein paar Codeschnipsel, die was damit zu tun haben:


```
public void componentResized(ComponentEvent e)
	{
		Dimension checkSize = new Dimension(this.getSize());

		int width = ((int)checkSize.getWidth() - 30) / 2;
		int height = (int)checkSize.getHeight() - 150;

		if (((int)checkSize.getWidth() < 640) || ((int)checkSize.getHeight() < 400))
		{
			this.setSize(640,400);
			width = (640 - 30) / 2;
			height = 400 - 150;
		}

		dbScroller.setPreferredSize(new Dimension(width,height));
		userScroller.setPreferredSize(new Dimension(width,height-30));

		if (this.isVisible())
		{
			SwingUtilities.updateComponentTreeUI(this);
		}
	}
```


```
JList dbList = new JList();
	JList userList = new JList();
```

Der darunter liegende Layoutmanager ist BorderLayout.


----------



## Ebenius (18. Nov 2003)

Laut Deinem Code-Schnipsel setzt Du die Größen der ScrollPanes so, dass diese größer als der umliegende Container sind und damit abgeschnitten werden, wenn der darumliegende Container kleiner als 640x400 pixel groß ist. Das kannst Du unmöglich wollen, zumal Du nicht mal die Positionen änderst.

Wenn ich mal rate, dann willst Du zwei JScrollPanes auf einem Panel (gleichgroß, nebeneinander, das Panel ausfüllend bis auf dreißig pixel abstand) haben und deren Inhalt soll mindestens 305x400px (resp. auch andere Werte) groß sein; oder größer, wenn es das Panel zulässt. Richtig? Das wäre einfach.

Oder willst Du, dass die JScrollPanes selbst Ihre Größe auch verändern? Falls ja, beschreib mal wie (mit Worten). Aber auch das ist nur unwesentlich schwieriger.

*Beides lässt sich ohne EventListener ganz sauber und ohne Seiteneffekte lösen!*

Bisher hab ich aber leider noch nicht kappiert, was genau Du machen willst (das geht leider aus Deinem Beispiel nicht hervor).

Grüße, Ebenius


----------



## Voltax (18. Nov 2003)

Hallo, 

hast Du schon probiert "invalidate" (auf eine der Components die innerhalb der Scrollpanes liegen) aufzurufen, bevor Du "validate" (auf die am weitesten außen liegende Componente) machst ? 

Grüße Voltax


----------



## Stefan1200 (20. Nov 2003)

Also, ich habe zwei JScrollPane (die beide eine JList beinhalten), beide haben die selbe größe, sollen nebeneinanderlegen und sollen nur einen 30 pixel spalt haben.

Ich möchte folgendes:
Falls der User das Fenster resized, sollen sich die JScrollPanes in der breite entsprechend anpassen, das es weiterhin nur 30 pixel abstand zwischen beiden sind. In der Höhe werden die JScrollPanes ja automatisch durch das BorderLayout vom darunter liegenden JPanel angepasst.
Der User soll aber das Fenster nicht kleiner resizen können, als 640x400.
Wenn er das macht, wird 640x400 als größe eingestellt.

Vielleicht ist diese Erklärung besser.


----------



## Ebenius (20. Nov 2003)

... dass Du so was einfaches willst. Getested mit JDK 1.4.1_02 auf Windows 2000.


*Zur Nutzung freigegeben* (man beachte das todo):

```
import java.awt.AWTEvent;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;

/**
 * JFrame with minimum size.
 * 
 * @author [email="ebenius@ebenius.com"]Ebenius[/email]
 * @version 1.0 / 20.11.2003
 */
public class JExtendedFrame extends JFrame
{
	/**
	 * Creates a new JExtendedFrame.
	 */
	public JExtendedFrame()
	{
		enableEvents(AWTEvent.COMPONENT_EVENT_MASK);
	}

	/**
	 * Updating size to minimum of 600 x 400 and calling overridden super 
	 * method.
	 * 
	 * @param e The component event
	 * @see java.awt.Component#processComponentEvent(java.awt.event.ComponentEvent)
	 * 
	 * @todo Implement bound properties for minimum width and height
	 */
	protected void processComponentEvent(ComponentEvent e)
	{
		synchronized (getTreeLock())
		{
			int width, height;
			if ((width = getWidth()) < 600 | (height = getHeight()) < 400)
				setSize(Math.max(600, width), Math.max(400, height));
		}

		super.processComponentEvent(e);
	}

	/**
	 * Test main method
	 */
	public static void main(String[] args)
	{
		JExtendedFrame f = new JExtendedFrame();
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(100, 100);
		f.show();
	}
}
```

Und das ohne Listeners, ohne revalidates, repaints, updateUIs und Graphikkartentreibertausch  :shock: 

Grüße, Ebenius


----------



## Guest (12. Aug 2008)

> Ich habe aber herausgefunden, wie es funktioniert.
> Wenn ich direkt nach dem setzen von setPreferredSize folgendes mache:
> *SwingUtilities.updateComponentTreeUI(this);*
> dann haut es wunderbar hin.



Tausend Dank! Diese Zeile hat mich nach einer frustrierenden Arbeit von zwei Stunden auf den richtigen Weg gebracht... Gruß


----------



## Marco13 (12. Aug 2008)

Vielleicht auf einen Weg, der dich zu deinem Ziel führt - aber der _richtige_ Weg ist das sicher nicht  :noe: 
(Sofern du nicht das L&F umstellst/umstellen willst) Diese Methode ist NICHT für Layout-Geschichten gedacht!


----------

