# Swing paintComponent();



## tuedel (30. Aug 2012)

Hallo an alle !! 

Ich habe eine kleine Verständnisfrage, mit der ich sicher gehen will, dass ich effizient mit der Zeichenfunktionalität von Swing umgehe.

Ich habe unzählige Swing Componenten, bei denen ich ein eigenes Aussehen in der paintComponent(); method vorgenommen habe. Was mich allerdings wundert ist, wie oft die Methode doch ausgeführt wird, obwohl laut einer Aussage diese nur dann gerufen wird wenn:

Die Komponente wird zum erstenmal sichtbar auf dem Bildschirm abgebildet.
Die Komponente wird in der Größe verändert.
Die Komponente wurde beschädigt und muß repariert werden (zum Beispiel wurde etwas verschoben, das vorher die Komponente verdeckte, und ein vorher verdeckter Teil der Komponente wird sichtbar).

Was aber zum Beispiel bei einem JPanel, dass ich als JButton fake (Mousevents die nen Enum State ändern und dann jeweils ein anderes Bild in der paintComponent() method zeichnen) passiert, ist das obwohl keine Interaktion mit dem Panel über die Maus erfolgt, die paintComponent permanent ausgeführt wird. Ich würde jetzt schlichtweg gern sicherstellen, ob dann nur geprüft wird, ob ein repaint notwendig ist, oder ob tatsächlich trotz keiner Veränderung die Component neu gezeichnet wird. 

Falls der Aufruf öfter erfolgt als notwendig, könnte das daran liegen, dass alle meine Komponenten von dem vorherigen Entwickler in einem JPanel gelegt worden sind?! In diesem wird eine Animation ausgeführt die permanent einen repaint auslöst. Falls das bedeutet, dass auch alle child componenten neu gezeichnet werden, wüsste ich die Ursache und einen hohen Performanzverlust.

Ich hätte letztlich nur gern Gewissheit, wie die pipeline exakt aussieht und ob ich in meinem Programm Handlungsbedarf habe ?!

Herzlichen Dank!!
LG
tuedel


----------



## Michael... (30. Aug 2012)

tuedel hat gesagt.:


> Falls der Aufruf öfter erfolgt als notwendig, könnte das daran liegen, dass alle meine Komponenten von dem vorherigen Entwickler in einem JPanel gelegt worden sind?! In diesem wird eine Animation ausgeführt die permanent einen repaint auslöst. Falls das bedeutet, dass auch alle child componenten neu gezeichnet werden, wüsste ich die Ursache und einen hohen Performanzverlust.


Lass doch einfach mal die Animation und das permanente repaint() in dem Container Panel weg, dann wirst Du feststellen, dass die anderen Komponenten ebenfalls nicht mehr so oft neu gezeichnet werden.
Grundsätzlich scheint mir ein animiertes/animierendes JPanel, welches weitere Komponenten enthält etwas fragwürdig.


----------



## Marco13 (30. Aug 2012)

tuedel hat gesagt.:


> Falls der Aufruf öfter erfolgt als notwendig, könnte das daran liegen, dass alle meine Komponenten von dem vorherigen Entwickler in einem JPanel gelegt worden sind?! In diesem wird eine Animation ausgeführt die permanent einen repaint auslöst. Falls das bedeutet, dass auch alle child componenten neu gezeichnet werden, wüsste ich die Ursache und einen hohen Performanzverlust.



Das bedeutet es. Wenn man repaint() aufruft, woher soll das Panel wissen, dass es bestimmte Teile DOCH nicht repainten muss? Das repaint() sollte in diesem Sinne möglichst "lokal" sein, also NUR auf der Component aufgerufen werden, die wirklich neu gezeichnet werden muss...


----------



## tuedel (31. Aug 2012)

Hallo und danke für die schnellen Antworten.

Ich habe mir den paint Prozess in meinem Programm nochmal genau angesehen. An sich hat wohl mein Vorgänger das Problem gehabt, dass wenn man die Komponenten, die nicht im eigentlichen Sinne Teil des animierenden Panels sind, als separierte Componenten im Contentpane durch das animierende Panel einfach "übermalt" werden. Es handelt sich dabei um eine Kartendarstellung die aufgrund der animation permanent geupdated werden muss. 

Abgesehen davon, dass er viel zu viel neu zeichnet wäre das bei einem panning prozess jedoch auf jeden Fall notwendig. Nun ist es allerdings so, dass bspw. verschiedene Menüs mit Metadaten sagen wir mal fixed über der Karte liegen. Da die aber bei Separation nicht nachgezeichnet werden, "übermalt" das animierende Panel die anderen Componenten. 

Vielleicht brauch ich nur einen Denkanstoß, aber wie könnte ich eine Componente "über" die animierende legen, ohne sie neu zeichnen zu müssen, oder permanent ein clipping durchzuführen. (Zumal sich beim pannen die Menüs ja nicht ändern und ich sie deswegen auch nicht neu zeichnen wollen würde).

Herzlichen Dank!!

LG 
Lou


----------



## Marco13 (31. Aug 2012)

Ich würde mir eher die Frage stellen, ob es schlimm ist, wenn irgendein Menü neu gezeichnet wird, wenn im Hintergrund eine Landkarte mit Animation usw. sowieso komplett neu gezeichnet wird. Es gibt zwar prinzipiell Dinge wie JLayeredPane, oder repaint(x,y,w,h), mit dem man genau den Bereich neuzeichnen lassen könnte, in dem NICHT das Menü zu sehen ist, aber ... wozu der Aufwand ...? :bahnhof:


----------



## tuedel (31. Aug 2012)

Hallo Marco,

der Aufwand ist insofern gerechtfertigt, dass bspw. Teile des Menüs aus JTable/ JLists bestehen, die unter anderem auch Stringoperationen mit jedem update ausführen müssen. Wenn ich jetzt 25 fps für die animation erreiche, erscheint mir ein 25faches repaint von Tabellen und ähnliches überflüssig und könnte die hohe CPU Last erklären (z.T. 50% +). 

Wenn ich bspw. eine der umfangreicheren Tabellen ausblende, sinkt die cpu last auf 20 %.

Daher würde ich es schon begrüßen, den Zeichenprozess intelligenter zu gestalten.


----------



## tuedel (31. Aug 2012)

Hm ich habe das JLayeredPane ausprobiert und folgendermaßen implementiert:


```
JLayeredPane content = new JLayeredPane();
        content.setLayout(null);

content.add(map, JLayeredPane.DEFAULT_LAYER);
        content.add(options, JLayeredPane.PALETTE_LAYER);
                
        setContentPane(content); // Applet container
```

Das Menü wird zwar nicht übermalt, der repaint wird jedoch immernoch permanent ausgeführt.
Irgendwas falsch gemacht?


----------



## Marco13 (31. Aug 2012)

Vielleicht hätte ich die JLayeredPane nicht so unreflektiert erwähnen sollen  ich weiß nicht, welche Auswirkungen ein "repaint" auf eine der Components im JLayeredPane hat (nebenbei: Sowas wie JLayeredPane, aber auch schon die ganz normalen painting-Mechanismen von Swing, mit RepaintManager, dirty rectangle detection & Co, sind VIEL(!) komplizierter, als sie aussehen ...  )

Es war nur ein Gedanke, dass man damit vielleicht das Neuzeichnen auf die Landkarten-Component beschränken kann. Ansonsten wäre eine Möglichkeit, zu versuchen, mit repaint(x,y,w,h) den zu Zeichnenden Bereich zu bestimmen. Inwieweit das optimizedDrawingEnabled-Flag bei solchen Sachen noch relevant ist, müßte man sich genauer überlegen.


----------



## tuedel (31. Aug 2012)

Was hälst du von einem separatem container wie einen internalframe oder ein jwindow. Die sollten ja dann gänzlich unabhängig vom contentpane des applets sein.


----------



## Marco13 (31. Aug 2012)

Vielleicht, vielleicht auch nicht. Da hilft nur ausprobieren. :bahnhof:

Ich wollte gerade mal schauen, ob das mit repaint(x,y,w,h) gehen könnte: Wenn man keinen RepaintManager setzt, wird trotzdem immer die GANZE component neu gezeichnet - offenbar bildet er einfach das Bounding Rectangle der Dirty-Bereiche (wenn man nicht versucht, um das Menü herum neu zu zeichnen, wird auch nur der entsprechende Bereich neu gezeichnet!). Wenn man aber, wie ich eben, NUR zum Debuggen (!) einen eigenen RepaintManager anfügt, der einfach die Aufrufe weiterreicht, zeichnet er auch nur die als dirty markierten Bereiche. Warum das so ist, weiß ich spontan nicht, aber das könnte man sich im RepaintManager sicher mal genauer ansehen


```
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;

class MapPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        System.out.println("Painting in map  "+g.getClip());
        g.setColor(Color.BLUE);
        g.fillRect(0,0,getWidth(),getHeight());
    }
}

class MenuPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        System.out.println("Painting in menu "+g.getClip());
        g.setColor(Color.GREEN);
        g.fillRect(0,0,getWidth(),getHeight());
    }
}

public class RegionPaintTest
{
    public static void main(String[] args)
    {
        initRepaintManager();
        SwingUtilities.invokeLater(new Runnable()
        {
            
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        final JPanel mapPanel = new MapPanel();
        mapPanel.setLayout(null);
        mapPanel.setPreferredSize(new Dimension(600,600));
        
        JPanel menuPanel = new MenuPanel();
        mapPanel.add(menuPanel);
        menuPanel.setBounds(0,0,200,200);
        
        f.getContentPane().add(mapPanel);
        f.pack();
        f.setVisible(true);
        
        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    for (int i=0; i<3; i++)
                    {
                        Thread.sleep(2000);
                        System.out.println("Trigger full repaint");
                        mapPanel.repaint();
                    }
                    for (int i=0; i<3; i++)
                    {
                        Thread.sleep(2000);
                        System.out.println("Trigger partial repaint");
                        mapPanel.repaint(201,0,400,600);
                        mapPanel.repaint(0,201,200,400);
                    }
                }
                catch (InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                
            }
        });
        t.start();
    }
    
    
    private static void initRepaintManager()
    {
        RepaintManager.setCurrentManager(new RepaintManager()
        {
            @Override
            public void addDirtyRegion(
                JComponent c, int x, int y, int w, int h)
            {
                super.addDirtyRegion(c, x, y, w, h);
                System.out.println("addDirtyRegion " + x + " " + y + " " + w + " " + h + " on " + c);
            }
            @Override
            public void paintDirtyRegions()
            {
                super.paintDirtyRegions();
            }
            
        });
    }
    
}
```


Wie auch immer, das bringt ja alles nichts: 
- Ändere das Layout, so dass das Menü außerhalb der Karte ist ODER
- Sorg' dafür, dass das Menü schnell gezeichnet werden kann (sollte nicht so schwer sein) ODER
- Find dich damit ab, dass es etwas langsamer ist (nur der Vollständigkeit halber  ) ODER
- Versuch' irgendwas zu frickeln, in der Hoffnung, dass es "was bringt", auch wenn es dadurch unwartbar wird...


----------



## tuedel (4. Sep 2012)

Hallo und danke Marco für deine Hilfe!!

Ich habe mich jetzt mit dem Clipping versucht, um dem Ganzen Herr zu werden. Ich habe eine Area von der Map erzeugt und die Bounds des Menüs ausgeschnitten.


```
mapBounds = new Area(map.getBounds());
        mapBounds.subtract(new Area(options.getBounds()));
```

Das dann in der paintComponent der Karte als clipping eingesetzt, sodass ich nicht über das Menü zeichne.


```
g2.setClip(JMain.getInstance().getMapBounds());
```

Jetzt wird der Bereich, bei dem sich das Menü befindet, nicht mehr neu gezeichnet. Allerdings wird jetzt stattdessen eine graue Fläche angezeigt. Wenn ich die Karte nicht anzeige, ist das Menü an der entsprechenden Position sichtbar. Ich habe zuerst die map und dann das menü zum contentpane des Applets hinzugefügt. Demnach sollte eigentlich der gewünschte Effekt zu sehen sein..?

LG


----------



## Michael... (4. Sep 2012)

tuedel hat gesagt.:


> Jetzt wird der Bereich, bei dem sich das Menü befindet, nicht mehr neu gezeichnet. Allerdings wird jetzt stattdessen eine graue Fläche angezeigt.


Kannst Du dazu mal kompilierbaren Bsp Code posten?
Vermutlich wird man dazu aber mit angemessenem Aufwand nicht eine zufriedenstellende Lösung finden, solange das Menü sich über der Karte befindet. Kann man die Karte evtl. aufteilen und z.B. auf drei JPanels darstellen, die um das Menü herumliegen?

Normalerweise sollte aber die Darstellung das Menüs im Verhältnis zum Neuzeichnen der Karte nicht sonderlich mehr Rechenaufwand bedeuten? Wie sieht es mit der Last aus wenn hier Standardkomponenten statt eigene verwendet werden? Wie schaut so eine paintComponent Deines Menüs aus?


----------



## Marco13 (4. Sep 2012)

Wann wird das clip gesetzt? Falls die Map ein JPanel ist, wird ggf. schon in
super.paintComponent(g);
der Hintergrund gelöscht. Evtl. könnte man da mit
mapPanel.setOpaque(false);
was machen, aber ... das ist alles ein bißchen hakelig...


----------



## tuedel (4. Sep 2012)

Hallo Michael,

an sich ist das von der Mechanik kein großes Ding.

Ein Applet/irgendein Heavyweight container, in dem sich die Karte (ein JPanel) befindet, in der die Tiles (oder bpsw. irgendeine Image) liegt. Dann muss ein Thread bestehen, der den repaint kontinuierlich ausführt. 

In das Contentpane dann ein zweites Panel, in dem dann alternative Informationen angezeigt werden.

Was das Aufteilen der Karte angeht - das habe ich auch überlegt, würde aber den Korrektionsaufwand nicht für das korrekte Zeichnen der Tiles rechtfertigen. Wenn man saubere Bounds festlegt, sodass die Karte in jedem Falle bspw. rechteckig wäre, wäre die saubere Trennung kein Problem. Da ich aber nicht ausschließen kann, dass die Menüs in Zukunft auch draggable sind - keine Lösung.

Was den Rechenaufwand angeht - hätte ich auch behauptet, dass das nicht unglaublich ins Gewicht fallen sollte. Die Metadaten Tabelle zeigt aber was anderes. Sind halt ca. 15-20 Zeilen, dessen repaint aber unzählige String Operationen enthält - sagen wir 15-20 x 10. Zumindest kann ich mir anders nicht die hohe CPU Last erklären, die auftritt, wenn diese Table sichtbar ist.

Mein Vorgänger hat versucht den Prozess des neu Zeichnens auszubremsen in dem er die paintComponent des scrollpanes angepasst hat, in dem sich die Tabelle befindet:


```
@Override
			public void paint(Graphics g) {

				long actTime = System.currentTimeMillis();
				long dif = actTime - lastTime;
				if (!isFocused() && dif < 250) {

					if (isBufferChanged()) {
						reDraw(g);
					}
				} else {
					isBufferChanged();
					reDraw(g);
					lastTime = actTime;
				}
				g.drawImage(store, 0, 0, null);
			}
```

Allerdings habe ich dann wieder den Fall, dass die gesamte Table neu gezeichnet wurde, obwohl sich bspw. von 1000 Datensätzen, nur 10% verändert haben. Ich nehme also die Gewalt über den redraw aus der Table und dem Tablemodel und lege sie in die Karte, die ich nicht in gleichem Maße unter Kontrolle habe.

Da ich das Problem gern lösen würde, wäre ich auch geneigt, die elegantere Methode auch auf "weniger" Rechenaufwändige Menüs anzuwenden. Wenn man effizienter arbeiten kann, will ich wegen Schwierigkeiten nicht den einfachen Weg gehen und "damit leben".

@ marco

Die map ist ein JXPanel dessen paintComponent wie folgt aussieht:


```
@Override
    protected void paintComponent(Graphics g) {
        if(backgroundPainter != null) {
            if (isOpaque()) {
                super.paintComponent(g);
            }
            
            Graphics2D g2 = (Graphics2D)g.create();            
            g2.setClip((Shape) JMain.getInstance().getMapBounds());
            
            
            try {
                SwingXUtilities.paintBackground(this, g2);
            } finally {
                g2.dispose();
            }
        } else {
            super.paintComponent(g);
        }
    }
```

Das Setzen von opague auf false habe ich versucht.


----------



## tuedel (4. Sep 2012)

Die beste mögliche Lösung könnte der Gedanke von einem Kollegen sein, ein JWindow zu verwenden. Durch die getrennte Container Instanz, beeinflussen sich die Heavyweight components nicht. 

Wenn ich dann zur Laufzeit die Größen anpasse, muss ich für die JWindows die Größen ändern, da ich ja kein opague setzen kann. Ich frag mich allerdings, ob das elegant ist, für die Menüs jeweils einen heavyweight container einzusetzen ?!

Was meint ihr?

Herzlichen Dank.
LG


----------



## Marco13 (4. Sep 2012)

tuedel hat gesagt.:


> Mein Vorgänger hat versucht den Prozess des neu Zeichnens auszubremsen in dem er die paintComponent des scrollpanes angepasst hat, in dem sich die Tabelle befindet:



Oh jeh... Was ist das denn alles? Der JScrollPane so ins Zeichnen reinzupfuschen ist heikel, wenn man bedenkt dass da ja auch noch ein Viewport und irgendwelche Blitting-Strategien dahinterliegen ... was "isBufferChanged" und "reDraw" genau machen würde ich ... bestenfalls aus Neugier wissen wollen... 



tuedel hat gesagt.:


> Die map ist ein JXPanel dessen paintComponent wie folgt aussieht:



Und der BackgroundPainter ist der, der das eigentliche Zeichnen des Bildes/Tiles durchführt? 

Ich würde erstmal versuchen, das Problem einzugrenzen. Irgendwas zu ändern hat meistens zur Folge, dass ... .... _irgendwas_ geändert wurde (sowas wie dieses "ausbremsen", da kommt man ja nur drauf, wenn man SEHR verzweifelt ist) und nachher traut sich niemand mehr, das rückgängig zu machen, weil man nicht weiß, ob es "wichtig" ist. 
Also... wenn du die spezielle Tabelle und das SEHR spzezielle Scrollpane mal ersetzt durch 

```
private JComponent createDummy()
{
    int rows = 100;
    int cols = 10;
    Object[][] rowData = new Object[rows][cols];
    Object[] columnNames = new Object[cols];
    for (int i=0; i<cols; i++)
    {
        columnNames = "Col"+i;
        for (int j=0; j<rows; j++) rowData[j][i] = "Cell"+i+","+j;
    }
    JTable table = new JTable(rowData, columnNames);
    return new JScrollPane(table);
}
```
ist es dann immernoch langsam? Hat die Tabelle, die da eigentlich angezeigt wird, einen eigenen CellRenderer? Wenn ja, wie sieht der aus? Wird da drin vielleicht eine Datenbankabfrage gemacht oder so?


----------



## tuedel (4. Sep 2012)

Also was im Moment schon ugly ist, dass das noch gar keine JTable ist, sondern eine JList - Zugleich ohne eigenes ListModel, um repaints auf updates auszuführen. Das heißt, dass er die Metadaten eines Objektes für jede Zeile neu auslesen und für die Darstellung anpassen muss (ja eigener cellrenderer).

Der Renderer macht halt die ganzen Stringoperationen. Kleines Beispiel:


```
@Override
	public Component updateComponent(C value, int index, boolean mouseOver) {

	      
		if (mouseOver) {
			setBackground(MouseOverColor);
		} else if (index % 2 == 0) {
			setBackground(zero);
		} else {
			setBackground(one);
		}
		for (LineEntry<C, ?> l : this.list) {
		      if(value!=null){
			l.update(value, index);
		      }
		}

		return linePanel;
	}
```

Das ist eine methode die von einem abstrakten Cellrenderer überschrieben wird und bei jedem getListCellRendererComponent(...) Aufruf ausgeführt wird. Da werden alle Einzeleinträge (JComponents) durchlaufen und geupdated - dabei ist der value das Object das die Meta Daten enthält. Die werden dann ausgelesen - angepasst wie bspw.:


```
@Override
            protected void update(Competitor source, JTextPane component, int index) {
                CompetitorKeyframeData inter = source.getInterpolationInfo().getKeyFrameData();
                if (inter != null && source.getInterpolationInfo().getStatus()) {
                    Integer d = inter.getDistToLeader();
                    if (d != null && d > 0) {
                        component.setText(parseDistance(d));
                    } else {
                        component.setText("-");
                    }
                } else if (!source.getInterpolationInfo().isSailMasterStatus()) {
                    component.setText("no data");
                } else if (inter != null && inter.getDistToLeader() != null) {
                    component.setText(parseDistance(inter.getDistToLeader()));
                }
                if (Config.isMatchRace() == true) {
                    setRscBasedBgColor(source.getRsc(), component);
                }
                if (followColor) {
                    toggleColor(source, component);
                }
            }
```

Also eine recht lange Kette, die ich anfangs auch nicht durchblickt habe und inzwischen als äußerst ineffizient ansehe. Ich möchte in Zukunft eine JTable einsetzen, mit eigenem TableModel um zellengenau updaten zu können. Das bringt nur nix, wenn die ohnehin 25x pro sek gezeichnet wird.

Ich bin gerade vom Mittag zurück und werd mal deinen Code einfügen.
brb.

Danke!!


----------



## Marco13 (4. Sep 2012)

Was das alles macht und wo das aufgerufen wird, sieht man da jetzt halt nicht... aber irgendwelche Berechnungen  (inter.getDistToLeader(), parseDistance(d) usw. ) um den Text in einer JTextPane (!? :autsch: ) zu setzen kann halt aufwändig sein. Es könnte sich lohnen, da mal genauer nachzusehen...


----------



## tuedel (4. Sep 2012)

Das ist es, deswegen soll statt der JList auch eine JTable rein, dessen TableModel mit den anzuzeigenden Daten geupdated werden soll, statt das im Renderer zu machen. 

Ich habe deine Beispiel tabelle eingefügt. Diese ist erwartungsgemäß schneller, auch wenn ich mit dem Krüppel von Rechner keine genauen Angaben machen kann. Allerdings hat die zZ gar keinen eigenen Renderer. Der käme auch bei der neuen JTable zum Einsatz, um die Inhalte gemäß des Datentyps anzupassen (bspw. Images usw.).

Ich denke du würdest vermuten, dass nicht der Zeichenprozess so langsam ist, sondern die JList, nicht wahr ?

An sich ist das richtig, könnte aber dennoch nicht den gewünschten Effekt haben. Updates erfolgen ohnehin oft, aber die müssen sich nicht noch mit den Zeichenprozessen überschneiden, dass wäre lediglich - das größere Übel (falls es das ist = ) ) auszumerzen. Das bedeutet aber nicht, dass das andere nicht genügend Einfluss ausübt. 

An sich könnte ich auch mit der Tabelle beginnen und dann prüfen, wieviel sich dadurch bessert. Allerdings halte ich es für semi gut die UI weiterzuführen, wenn ich die hierarchy doch noch ändern muss. Ich will den Code quasi nicht mehrfach umschreiben müssen.

Ansonsten gibt es aber kein wirklich großes Loch im Renderer. Quasi keine aufwendigen Berechnungen. Lediglich eine Menge Stringarbeit und setText Aufrufe halt.

Danke.
LG


----------



## tuedel (4. Sep 2012)

Achja was hälst du jetz eigentlich von dem JWindow. Das scheint bisher den Anforderungen zu genügen. Liegt definitiv vorn. Beeinflusst sich nicht gegenseitig und unterstützend könnte ich trotzdem die Clipping Area setzen, um noch ein wenig in der Karte zu sparen.

Hier wird jedenfalls nicht permanent die UI mitgezeichnet (habe ein Auswahlmenü mit Comoboxes und eigenem Renderer und Tablemodel zum üben geschrieben). Der Renderer wird exakt nur zum einblenden aufgerufen.


----------



## Marco13 (4. Sep 2012)

Ich kann nicht einschätzen, ob und wie man ein JWindow einsetzen könnte, um das Problem zu lösen (wann braucht man sonst schon mal ein JWindow?  ). Aber ich kann nachvollziehen, dass man versucht, dem Lava flow (programming) - Wikipedia, the free encyclopedia mit möglichst wenig Aufwand zu entkommen.


----------



## Michael... (4. Sep 2012)

Das ganze schaut mir nach einem fehlerhaften Konzept aus. Unter dem Aspekt, dass ein Renderer im Paint Prozess einer solchen Komponente (egal ob JList oder JTable) eine wichtige Rolle spielt, sollte man irgendwelche Berechnungs/Bestimmungsprozesse die für ein Graphikupdate nicht relevant sind aus diesem Prozess raushalten. Solche relevanten Informationen wie der Text der dargestellt werde soll, müssen m.M. schon "vor" dem Zeichenprozess vorliegen und im Renderer nur abgeholt werden. Es macht ja keinen Sinn einen Wert der sich nicht geändert hat bei jedem Neuzeichnen neu zu bestimmen. Der Trigger zur Neubestimmung muss aus einer anderen Ecke kommen.
Von daher sollte man das Konzept vor allem unter dem Aspekt möglicher Weiterentwicklungen überarbeiten. Alles andere ist nur ein Workaround und geht früher oder später wieder nach hinten los.


----------



## tuedel (4. Sep 2012)

Jo Michael, so seh ich das auch. Deswegen will ich auch in Zukunft zu einem eigenen TableModel, bei dem das Update von woanders kommt und dann lediglich der Renderer die Anzeige übernimmt. Ansonsten was das JWindow angeht - keine zusätzliche UI (Border, Header usw.). Dazu liegt es definitiv vor des ContentPane und ich muss deswegen dessen Inhalt nicht neu zeichnen, auch wenn "dahinter gezeichnet" wird.

Es sieht für mich so aus, als wäre das eine der wenigen Möglichkeiten um bei dem UI Aufbau dem repaint zu entkommen.

Danke für eure Hilfe!!


----------



## tuedel (18. Sep 2012)

Hallo !!

Ich melde mich mal wieder, weil ich doch noch einen anderen Gedanken hatte, wie man die Problematik lösen könnte. Mein Gedanke ging in die Richtung die Karteninhalte zu trennen. In diesem Zuge müsste ich den Hintergrund, der ja ohne drag/zoom nur 1x gezeichnet werden muss in einem layeredPane mit der niedrigsten Order versehen. Sämtliche Inhalte, die sich auf der Karte befinden, könnten in einem separatem durchsichtigem Panel gezeichnet werden, sodass ich abhängig der darzustellenden Elemente den repaint steuern könnte.

Ich habe mir als Möglichkeit vorgestellt, die UI elemente in einer Map mit entsprechenden Enums und deren relativen Position zum Applet zu mappen. Während des Zeichenprozesses dann zu prüfen, ob sich das zu zeichnende Objekt innerhalb der boundaries befindet. Dadurch könnte der objekt repaint und toplayer repaint umgangen werden. Wenn das Objekt nur z.T. innerhalb der Boundaries liegt, könnte man den entsprechenden Teil im repaint des Toplayers festlegen, um nicht die gesamte UI neu zu zeichnen.

Das einzige was mich daran stört ist, dass ich eigentlich keinen Plan habe, ob ich mit solchen permanenten Vergleichen nicht genauso schnell/langsam bin, wie wenn ich die Toplayer neu zeichnen würde. - wobei das widerum vom Inhalt des Toplayers abhängt. 

Vielleicht schafft dieser Gedanke Anreize für weitere Diskussionen, wie sich Animationen in Swing aus Sicht der Konzeption gut umsetzen lassen oder ob jemand eine Aussage dazu treffen kann, wie stark sich Vergleichsoperationen im Gegensatz zu repaints auswirken können. 

Herzlichen Dank!!

LG
tuedel


----------



## Marco13 (18. Sep 2012)

Ich glaube das steht und fällt mit der Frage, die noch über allem schwebt: Warum muss das Zeichnen eines Menüs so aufwängig sein?


----------

