# Reihenfolge ?



## Verjigorm (1. Okt 2007)

hallo, ich hab da mal ne Frage

und zwar habe ich ein JFrame mit JPanels (in Reihen und Spalten) drauf, die beim start beliebig farbig initialisiert werden


```
for(int i=0; i < ANZAHL_REIHEN; i++)
        for(int j=0; j < ANZAHL_SPALTEN; j++)
            panelarray[i][j].setBackground(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));
```

funktioniert auch ohne Probleme

Was mich aber wundert ist, dass die Felder sich nicht in der Reihenfolge des Schleifendurchlaufs färben (also von links oben nach rechts unten) sondern irgendwie kreuz und quer!? (bei sehr grosser Anzahl von Feldern sieht man das sehr schön)

woran liegt das denn?
kann man das irgendwie erzwingen? (nur interesse halber)

mfg Verjigorm


----------



## tuxedo (1. Okt 2007)

Swing führt eben nach eigenen Regeln einen Repaint aus. Erzwingend könntest du das neuzeichnen und somit einfärben des jeweiligen panels mit "repaint()". Aber das ist sicher nicht wirklich performant. 

- Alex


----------



## Marco13 (1. Okt 2007)

Über die Performance braucht man sich bei sowas keine so großen Gedanken zu machen: Ein repaint wird dann aussgeführt, wenn es passt. D.h. selbst wenn man überall explizit ein "repaint" dazuschreibt, ist nicht garantiert, dass sie die Farben der Reihe nach ändern...


----------



## tuxedo (1. Okt 2007)

wieder was dazu gelernt. Dachte mit "repaint" kann man das ganze forcieren...?

- Alex


----------



## Verjigorm (1. Okt 2007)

hm also ich hab mal ein repaint() dazugepackt
egal ob ich das reepaint() in der inneren/äußeren oder komplett nach den 2 schleifens chreibe, der Frame wird erst aktualisiert, wenn BEIDE schleifen durchgelaufen sind.

Vermutlich aus Optmierungsgründen könnte ich mir vorstellen ... *schulterzuck*

finds schon witzig, was manchmal für Effekte auftreten ^^


----------



## SlaterB (1. Okt 2007)

erstmal: das sind nicht betont zwei Schleifen, die innere wird ja mehrmals durchlaufen, 
BEIDE klingt dann komisch

und wie nun?, wenn repaint() erst am Ende durchgeführt wird, wieso beobachtest du dann irgendeine Art von Reihenfolge?


----------



## Verjigorm (1. Okt 2007)

SlaterB hat gesagt.:
			
		

> und wie nun?, wenn repaint() erst am Ende durchgeführt wird, wieso beobachtest du dann irgendeine Art von Reihenfolge?



habe ich nirgendwo geschrieben beim repaint() ...
ich seh halt nur den komplett aktualisierten frame


----------



## SlaterB (1. Okt 2007)

> habe ich nirgendwo geschrieben 

->
> der Frame wird erst aktualisiert, wenn BEIDE schleifen durchgelaufen sind. 

ob repaint() oder Aktualiserung, was passiert nun genau?,
wird ständig aktualisiert, so dass einzeln neue Farben erscheinen
oder nur EINMAL am Ende aktualisiert, so dass alle JPanel auf einem Schlag ihre Farbe erhalten?

ein lauffähiges komplettes Testprogramm wäre hilfreich..


----------



## Verjigorm (1. Okt 2007)

EIN repaint() NACH den Schleifendurchgängen!


----------



## SlaterB (1. Okt 2007)

das hast du schon gesagt, den Rest aber immer noch nicht:

wird ständig aktualisiert, so dass einzeln neue Farben erscheinen 
oder nur EINMAL am Ende aktualisiert, so dass alle JPanel auf einem Schlag ihre Farbe erhalten?

und vor allem, wie die einmalige Färbung aller Panels zu 

> Was mich aber wundert ist, dass die Felder sich nicht in der Reihenfolge des Schleifendurchlaufs färben (also von links oben nach rechts unten) sondern irgendwie kreuz und quer!?

passt


der ganze Topic-Titel 'Reihenfolge' steht in Frage, wenn es nur ein repaint() gibt


----------



## Verjigorm (1. Okt 2007)

SlaterB hat gesagt.:
			
		

> wird ständig aktualisiert, so dass einzeln neue Farben erscheinen
> oder nur EINMAL am Ende aktualisiert, so dass alle JPanel auf einem Schlag ihre Farbe erhalten?



gna ...........................................................................

EINMAL AM ENDE ZUM DRITTEN MAL!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *tasteklemm*

zum mitschreiben  :

ohne repaint():
Aktualisierung der Panels kreuz und quer, relativ langsam, quasi zum zuschauen (ab ca.20x20 Panels)

mit einem repaint() entweder in der innersten Schleife, in der äußeren Schleife oder nach den Schleifen:
komplette Aktualisierung aller Panels "auf einmal"

was halt auffällt: 
mit repaint() ist das ganze 10mal so schnell wie ohne repaint()


----------



## tuxedo (1. Okt 2007)

Und wenn du dir den Java-Doc Teil zu "repaint()" anschaust siehst du auch wieso...

- Alex


----------



## SlaterB (1. Okt 2007)

@Verjigorm:
sag das doch gleich 
ok, kann man aus dem ersten Posting dazu schon irgendwie rauslesen, ich jedoch nicht 

@alex:
wie kann es sein, dass das Vorhandensein eines beliebigen Befehls NACH der Schleife die Schleife selber schneller ablaufen lässt?
(unter der Annahme, dass die lange Dauer auf die Schleife zurückzuführen ist)
das würde mich auch interessieren, kann dazu nix nachlesen?

--------

mal ein Testprogramm:
bei mir wird da durch repaint() nie irgendwas schneller,
ein repaint() in der Schleife führt bei mir aber manchmal teilweise zu einer Links-oben-rechts-unten-Reihenfolge wie gewünscht,
mit Thread.sleep(10); dahinter läßt sie sich bei mir erzwingen, ist aber unsauber und kaum verlässlich, noch langsamer sowieso



```
public class TestGUI
    extends JFrame
{

    public TestGUI()
        throws Exception
    {

        setLayout(new FlowLayout());

        JPanel[] a = new JPanel[1000];
        for (int i = 0; i < a.length; i++)
        {
            a[i] = new JPanel();
            a[i].setBackground(new Color((i * 10) % 250, 30, 30));
            add(a[i]);
        }


        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 400);
        setVisible(true);

        Thread.sleep(2000);

        for (int i = 0; i < a.length; i++)
        {
            int k = (int)(Math.random() * 250);
            a[i].setBackground(new Color(k, k, k));
            repaint();
            Thread.sleep(10);
        }
        repaint();
    }

    public static void main(String[] args)
        throws Exception
    {
        new TestGUI();
    }
}
```


----------



## tuxedo (1. Okt 2007)

Naja, das mit dem "schneller" hab ich jetzt nicht auf die Ausführungegeschwindigkeit bezigen verstanden, sondern auf "schneller bei der aktualisierung der einzelnen Panels".

Wenn man die Farbe ändert und keinen repaint() auslöst, und swing selbst auch nix unternehmen würde, würden sich die Felder nie ändern. Swing löst aber hier und da mal ein repaint aus (z.B. wenn das Fenster verschoben wird, oder wenn man irgendwo hinklickt). Was genau alles neu gezeichnet wird ist unter anderem abhängig vom Event (verschieben, scrollen, klicken etc...). 

Wenn man jetzt selbst ein repaint() auslöst kommt man dem "swing löst _irgendwann_ einen repaint aus" zuvor. 
Ich dachte bisher nur dass repaint() SOFORT ein neuzeichnen veranlasst. Aber in der Javadoc/Quellcode steht ja:



> /**
> * Repaints this component.
> *
> 
> ...


----------



## Verjigorm (1. Okt 2007)

also ich hab folgendes Programm:


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

public class Change_BGColor extends JFrame implements ActionListener
{
	private static final long serialVersionUID = 6246486124691661219L;
	private JPanel haupt_panel = new JPanel();
	private JPanel button_panel = new JPanel();
	private JPanel panel = new JPanel();
	private final int ANZAHL_REIHEN = 50;
	private final int ANZAHL_SPALTEN = 50;
	private JPanel panelarray[][] = new JPanel[ANZAHL_REIHEN][ANZAHL_SPALTEN];
	private JButton start = new JButton("start");
	private boolean init = false;
	private static final Random r = new Random();

	public Change_BGColor()
	{
		super("Titel");
		setLocation(50,50);
		setSize(640,480);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		haupt_panel.setLayout(new BorderLayout());
		start.addActionListener(this);
		button_panel.add(start);

		panel.setLayout(new GridLayout(ANZAHL_REIHEN,ANZAHL_SPALTEN));
		panel.setBackground(Color.BLUE);

		init();

		haupt_panel.add(button_panel,BorderLayout.NORTH);
		haupt_panel.add(panel);
		add(haupt_panel);
		pack();
		setVisible(true);
	}

	public static void main(String[] args)
	{
		new Change_BGColor();
	}

	public void actionPerformed(ActionEvent e)
	{
		if(init)
			random_BGColor();
		else
			init();
	}

	private void random_BGColor()
	{
		for(int i=0; i < ANZAHL_REIHEN; i++)
			for(int j=0; j < ANZAHL_SPALTEN; j++)
				panelarray[i][j].setBackground(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));
		repaint();
		init = false;
	}

	private void init()
	{
		for(int i=0; i < ANZAHL_REIHEN; i++)
		{
			for(int j=0; j < ANZAHL_SPALTEN; j++)
			{
				if(panelarray[i][j] == null)
				{
					panelarray[i][j] = new JPanel();
					panelarray[i][j].setBorder(new BevelBorder(BevelBorder.RAISED));
					panel.add(panelarray[i][j]);
				}

				panelarray[i][j].setBackground(Color.RED);
			}
		}
		repaint();
		init = true;
	}
}
```

wenn ich da die 2 repaint() wegmache läuft es megalangsam 

das ganze hat zwar fast nix damit zutun, was ich eigentlich machen wollte, hat sich aber so ergeben


----------



## SlaterB (1. Okt 2007)

hübsche Spielerei,
bei mir hat das Weglassen der  repaint() keine Auswirkung,


----------



## tuxedo (1. Okt 2007)

Das repaint in init() ist unnötig. Auch die init-variable ist n bisschen unnötig. Habs melr geringfügig gekürzt (mich hatte die fallunterscheidung in actionPerformed irritiert):


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

public class Change_BGColor extends JFrame implements ActionListener
{
   private static final long serialVersionUID = 6246486124691661219L;
   private JPanel haupt_panel = new JPanel();
   private JPanel button_panel = new JPanel();
   private JPanel panel = new JPanel();
   private final int ANZAHL_REIHEN = 50;
   private final int ANZAHL_SPALTEN = 50;
   private JPanel panelarray[][] = new JPanel[ANZAHL_REIHEN][ANZAHL_SPALTEN];
   private JButton start = new JButton("start");
   private static final Random r = new Random();

   public Change_BGColor()
   {
      super("Titel");
      setLocation(50,50);
      setSize(640,480);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      haupt_panel.setLayout(new BorderLayout());
      start.addActionListener(this);
      button_panel.add(start);

      panel.setLayout(new GridLayout(ANZAHL_REIHEN,ANZAHL_SPALTEN));
      panel.setBackground(Color.BLUE);

      init();

      haupt_panel.add(button_panel,BorderLayout.NORTH);
      haupt_panel.add(panel);
      add(haupt_panel);
      pack();
      setVisible(true);
   }

   public static void main(String[] args)
   {
      new Change_BGColor();
   }

   public void actionPerformed(ActionEvent e)
   {
         random_BGColor();
   }

   private void random_BGColor()
   {
      for(int i=0; i < ANZAHL_REIHEN; i++)
         for(int j=0; j < ANZAHL_SPALTEN; j++)
            panelarray[i][j].setBackground(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));
      repaint(); // selbst getriggertes repaint()
   }

   private void init()
   {
      for(int i=0; i < ANZAHL_REIHEN; i++)
      {
         for(int j=0; j < ANZAHL_SPALTEN; j++)
         {
            if(panelarray[i][j] == null)
            {
               panelarray[i][j] = new JPanel();
               panelarray[i][j].setBorder(new BevelBorder(BevelBorder.RAISED));
               panel.add(panelarray[i][j]);
            }

            panelarray[i][j].setBackground(Color.RED);
         }
      }
   }
}
```

Das "megalangsam" kann ich nicht nachvollziehen...Bei mir läufts ohne das repaint() auch <1sek... Mit repaint ist es beinahe in 0 Sekunden über die Bühne.

Und die erklärung liegt nach wie vor in der Doku zu repaint:



> Otherwise, this method causes a call to this component's <code>update</code> method as soon as possible.



Wenn du das repaint weglässt, kümmert sich swing selbst um das triggern des neuzeichnens. Ich vermute mal dass hier eine Art Kettenreaktion ausgelöst wird. Triggerst du repaint selbst, so hast du keine kette, sondern eine zeitgleiche änderung aller beteiligten Komponenten. 

- Alex


----------



## tuxedo (1. Okt 2007)

Ach ja, noch was:


```
private void random_BGColor()
   {
      for(int i=0; i < ANZAHL_REIHEN; i++)
         for(int j=0; j < ANZAHL_SPALTEN; j++) {
            panelarray[i][j].setBackground(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));
            panelarray[i][j].repaint(); // selbst getriggertes repaint()
         }
      
   }
```


```
private void random_BGColor()
   {
      for(int i=0; i < ANZAHL_REIHEN; i++)
         for(int j=0; j < ANZAHL_SPALTEN; j++) 
            panelarray[i][j].setBackground(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256)));
      repaint(); // selbst getriggertes repaint()
   }
```

Siehst du nen unterschied? letzteres ist die "schnellere" zeichenvariante ... Und ersteres wird Swing intern machen wenn du repaint() ganz weglässt.

- Alex


----------



## Verjigorm (1. Okt 2007)

jo, das war aus dem Gesamtprogramm rausgebrochen und nicht wirklich schön der Quellcode....
"init" war dazu da um die Felder abwechseln bunt bzw einfarbig zu färben, bei jedem zweiten Tastendruck halt...

mit repaint() dauerts bei mir ~1sek
OHNE repaint 8-10sekunden


----------



## tuxedo (1. Okt 2007)

Was für ne lahme Kiste hast du denn? 8..10 Sekunden? Hab hier nen Standard PC ohne spezielle 3D Grafikkarte...

- Alex


----------



## Verjigorm (1. Okt 2007)

Standard-Firmen-Laptop


----------



## tuxedo (1. Okt 2007)

Naja, dann benutz halt einfach das einmalige repaint und gut ist. [joke]Oder wechsle die Firma und lass dir nen gescheiten PC/Laptop  geben ;-)[/joke]

- Alex


----------



## Verjigorm (1. Okt 2007)

alex0801 hat gesagt.:
			
		

> Naja, dann benutz halt einfach das einmalige repaint und gut ist. [joke]Oder wechsle die Firma und lass dir nen gescheiten PC/Laptop  geben ;-)[/joke]
> 
> - Alex



ab 1.11. Diplomarbeit in anderer Firma


----------



## tuxedo (1. Okt 2007)

Na dann: have some fun ;-) 
Ich hab meine 4 Wochen später dann endlich abgeschlossen (wenn ich mich hier im Forum mal losreissen kann...)

- Alex


----------



## Marco13 (1. Okt 2007)

Jo, man kann wohl davon ausgehen, dass das hand-getriggerte "repaint" die vielen kleinen einzelnen repaints (die durch das setzen der Hitnergrundfarbe entstehen) überlagert. Da gibt's unter anderem die Klasse RepaintManager mit einem Field

```
Hashtable dirtyComponents
```
(was die "zufällige" Reihenfolge der Farb-Änderungen erklärt!!!) und Methoden wie "addDirtyRegion"...
_
* Add a component in the list of components that should be refreshed.
* If c already has a dirty region, the rectangle (x,y,w,h) 
* will be unioned with the region that should be redrawn. 
_
D.h. in der Schleife setzt er wohl die ganzen Hintergrundfarben, und merkt sich jedes einzelne Panel als "dirty", und am Ende updatet er alle Panels - in der ("zufälligen") Reihenfolge, wie sie in der HashTable liegen. Wenn man stattdessen EIN mal repaint macht, gibt es nurnoch EINE "dirty component", und das ist der ganze Frame...


----------



## Verjigorm (2. Okt 2007)

hm klingt vernünftig


----------



## tuxedo (2. Okt 2007)

Jepp, das war gut recherchiert. So in der Art hab ich mir's auch vorgestellt, nur war ich zu faul gaaaanz genau nachzusehen ;-)

Aber gut dass wir das nun geklärt haben ...


----------

