# Swing und VolatileImage



## SlippyStoat (3. Dez 2010)

Hallo,

würde gerne eine Daisy's Garten 2 Clone in Java programmieren. Habe dieses grandiose Java Tutorial von Quaxli gefunden (in dem leider die Seitenzahlen fehlen ;-) ).

Bin soweit ziemlich gut zurecht gekommen, jedoch stecke ich bei einem Problem fest, bei dem ich mich einfach mal hier melden muss. Für die Spiel GUI verwende ich jede Menge JComponents. (JFrame, JMenuBar, JToolBar, BorderLayout, JScrollPane, JViewport...) Auf diese möchte ich nicht verzichten, aber denoch ein Hardware-Rendering für mein Spiel haben, weil es im Softwaremodus extrem langsam läuft. Die relativ großen Tiles und die Sprites bestehen alle aus PNG's mit Alpha Channels.

Jetzt habe ich versucht, wie im Tutorial, die Performance mit Canvas und VolatileImage zu verbessern. Das man AWT und Swing nicht mischen sollte ist mir klar, aber gibt es trotzdem eine Möglichkeit eine Hardwarebeschleunigung mit Swing zu verwenden?

Das JFrame habe ich nicht wie im Tutorial beschrieben durch Frame ersetzt, weil ich ja die JComponents alle brauche, deshalb wahrscheinlich dieser Fehler:


> Exception in thread "main" java.lang.IllegalStateException: Component must have a valid peer
> at java.awt.Component$FlipBufferStrategy.createBuffers(Unknown Source)
> at java.awt.Component$FlipBufferStrategy.<init>(Unknown Source)
> at java.awt.Component$FlipSubRegionBufferStrategy.<init>(Unknown Source)
> ...



Grüße

SlippyStoat

PS: Finde es toll, das man hier Beiträge als Gast schreiben kann, aber da ich eine E-Mail Benachrichtigung wünsche, habe ich mich trotzdem mal angemeldet. :-D


----------



## Guybrush Threepwood (3. Dez 2010)

Meines Wissens läuft Swing seit 1.6.0_10 mit Hardwarebeschleunigung. Ich verwende auch häufig VolatileImages in Swing, aber Deinen Fehler hatte ich bis jetzt noch nie. Man kann problemlos auch auf Swing-Komponenten VolatileImages zeichnen. Poste doch mal ein Beispiel.


----------



## SlippyStoat (3. Dez 2010)

Es ist erst mal ein Grundlegendes Verständnisproblem. Die richtige Frage muss eigentlich lauten: 
*
Wie bekomme ich eine Hardwarebeschleunigung mit Swing hin?*

Weil der eigentliche Fehler tritt bei der Erzeugung einer BufferStrategy auf. Brauche ich sie bei Swing in Kombination mit VolatileImage überhaupt? Wie verwende ich VolatileImages in Swing?

Das Codebeispiel wäre etwas komplexer, weil die Klassen schon aus mehreren hundert Zeilen Code bestehen. Es ist halt im Moment so wie im Tutorial beschrieben (*S. 128ff*), außer das ich eben noch ein JFrame statt einem normalen Frame verwende und mein GamePanel liegt im JViewport des JScrollPane.


----------



## Guybrush Threepwood (3. Dez 2010)

Die Swing-Komponenten sind bereits double buffered per default (Painting in AWT and Swing) und der Offscreen-Buffer benützt meines Wissens ein VolatileImage. Siehe auch: http://java.sun.com/j2se/1.4/pdf/VolatileImage.pdf (dort gibt es auch Code-Beispiele zur Verwendung von VolatileImages).


----------



## SlippyStoat (7. Dez 2010)

Danke. Ich werd's mir mal anschauen.


----------



## Steev (8. Dez 2010)

Der Fehler kommt immer dann, wenn man eine BufferStrategy erstellt und die Komponente, für die die Strategy erstellt wird noch nicht visible ist...


----------



## SlippyStoat (27. Dez 2010)

Guybrush Threepwood hat gesagt.:


> Die Swing-Komponenten sind bereits double buffered per default (Painting in AWT and Swing) und der Offscreen-Buffer benützt meines Wissens ein VolatileImage. Siehe auch: http://java.sun.com/j2se/1.4/pdf/VolatileImage.pdf (dort gibt es auch Code-Beispiele zur Verwendung von VolatileImages).



Also die beiden Links haben mir wenig gebracht, zudem das PDF über VolatileImage etwas veraltet zu sein scheint. Kein Wunder, ist ja auch java 1.4, oder? Bereits beim kompilieren vom Beispielcode werden Warnungen ausgegeben, dass es eine "deprecated" API benutzt bzw. überschreibt.

Inzwischen hat mein Spiel einiges an Funktionalität gewonnen (u.a. umschalten zwischen gif und png Grafiken) und habe wieder Zeit für diese VolatileImage Thematik gefunden. Nach langer Suche bin ich dauernd darauf gestoßen, dass VolatileImage angeblich keine "translucent Images" darstellen kann. Ist das mit Java 6 auch noch immer so? Weil das bringt mir im Bezug auf png-Grafiken dann ja gar nichts (bzgl. Kantenglättung). 

Bin auch auf diese interessante (leider unbeantwortete) Frage hier gestoßen: 
http://www.java-forum.org/awt-swing-swt/26642-volatileimage.html


----------



## Guybrush Threepwood (27. Dez 2010)

VolatileImage verfügt immer noch nicht über einen Alpha-Kanal (zumindest ist es mir bislang nicht gelungen).
Der unter dem Post dargestellte Code scheint mir nicht recht sinnvoll zu sein. Brauchst Du eine Funktion, um eine Grafik in ein VolatileImage zu laden?


----------



## SlippyStoat (27. Dez 2010)

D.h. das Ruckeln mit png-Grafiken kann man also nicht abstellen!? Ich dachte im 21. Jahrhundert könnte man endlich Spiele mit hübschen png-Grafiken gestalten, statt verpixelten gif-Grafiken wie zu Windows 98 Zeiten. :autsch:
Wohl nicht mit Java; doof, das wir unsere Studienarbeit mit Java schreiben müssen. 

Ja, so eine Funktion wäre recht nützlich. 
Mich wundert's nur, dass ich in der Java API keine passenden Methoden zu VolatileImage zum Bilder laden gefunden habe.

Vielleicht noch ein paar Details zur Grafik des Spiels:
Die Map kann mal aus 200 Tiles, je 100x100 Pixel groß, bestehen. Dabei kann ein einzelnes Tile bis zu 3 Bildebenen und eine gif-Maske bestehen. Zusätzlich können auf jedem Tile beliebige Items liegen und letztlich die animierte Spielfigur aus png-Grafiken. Der parallaxe jpg-Hintergrund ist wohl weniger erwähneswert. Beim Umschalten der Qualität werden Bildebenen der Tiles und Items durch gif bzw. png ersetzt.
Das ganze läuft in einem eigenen Thread, der alle 10 Millisekunden neu gezeichnet wird.


----------



## Guybrush Threepwood (27. Dez 2010)

Naja, bei BufferedImages ist die Transparenz kein Problem und man kann dieses schließlich in ein VolatileImage kopieren. Hier mein Code, mit dem ich Bitmapdateien in ein VolatileImage lade:

```
public static VolatileImage loadVolatileImage(String filename, int width,
			int height) {
		BufferedImage bimage = loadImage(filename);
		VolatileImage vimage = createVolatileImage(width, height,
				Transparency.OPAQUE);
		Graphics2D g = null;

		try {
			g = vimage.createGraphics();
			g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
					RenderingHints.VALUE_INTERPOLATION_BILINEAR);
			g.drawImage(bimage, 0, 0, width, height, null);
		} finally {
			g.dispose();
		}

		return vimage;
	}
```


```
public static BufferedImage loadImage(String ref) {
		BufferedImage bimg = null;
		try {

			bimg = ImageIO.read(new File(ref));
		} catch (Exception e) {
			System.err.println("Error loading image file " + ref);
			e.printStackTrace();
		}
		return bimg;
	}
```


```
private static VolatileImage createVolatileImage(int width, int height,
			int transparency) {
		GraphicsEnvironment ge = GraphicsEnvironment
				.getLocalGraphicsEnvironment();
		GraphicsConfiguration gc = ge.getDefaultScreenDevice()
				.getDefaultConfiguration();
		VolatileImage image = null;

		image = gc.createCompatibleVolatileImage(width, height, transparency);

		int valid = image.validate(gc);

		if (valid == VolatileImage.IMAGE_INCOMPATIBLE) {
			image = createVolatileImage(width, height, transparency);
			return image;
		}

		return image;
	}
```

Falls Du die Transparenz hinkriegst würde ich mich über eine Nachricht freuen.


----------



## SlippyStoat (27. Dez 2010)

Danke für den Code.

Habs ausprobiert. Die Transparenten Bereiche werden weiß gezeichnet. D.h. alle Grafiken sind rechteckig und das was unsichtbar sein sollte, wird weiß gezeichnet. Was mich wundert, das Spiel ruckelt mindestens genau so stark als wenn ich ausschließlich BufferedImage verwenden würde.


----------



## SlippyStoat (28. Dez 2010)

Bin (endlich) auf die Idee gekommen, VOR dem zeichnen der Bilder abzufragen, ob die Tiles bzw. Items sich überhaupt im sichtbaren Bereich des Viewports liegen. Das gab einen gewaltigen Performance Schub. Läuft jetzt sogar beinahe ruckelfrei mit PNG-Grafiken. 

Noch ein bischen mehr Performance könnte man vielleicht bekommen, wenn man die Tiles bzw. Items vor dem zeichnen exakt an den Rändern mit getSubImage() abschneidet. Das gilt auch für das parallaxe Hintergrundbild. Aber da gibt's noch genügend andere Sachen zu implementieren.


----------



## Ein Keks (28. Dez 2010)

Zum Thema VolatileImage:
VolatileImages sind wie der Name sagt flüchtig (zumindest unter Windows). Damit sind sie nur für dynamische Inhalte (z.B. als Backbuffer) zu gebrauchen. Für statische Inhalte wie png-Grafiken sollten BufferedImages verwendet werden (die übrigens auch häufig ne Kopie im VRAM haben).

Für kleine Performance-Steigerung sollte man sich die Klasse GraphicsConfiguration mal ansehen (vorallem createCompatibleImage - allerdings ist das ja auch schon in Quaxlies Tutorial drin).
Am wichtigsten ist aber nunmal dein Code (wie du ja schon gemerkt hast). Vermeide unnötige Object erzeugungen und andere teure Operation in der paintComponent-Methode und natürlich auch unnötiges zeichnen (aber ohne Einblick in den Code kann dir diesbezüglich hier niemand groß weiterhelfen).

Und zum Thema Active Rendering: Wirklich große Unterschiede bringt das erst, wenn du mit Fullscreen-Exclusive Mode arbeitest (außer dass bei Passive Rendering ein kleines Delay zwischen repaint() aufruf und wirklichen Rendern auftreten kann bzw. Java teilweise mehrere Repaint()-aufrufe zusammenfasst (was in deinem Fall wohl eher ein Vorteil wäre)).


----------



## SlippyStoat (29. Dez 2010)

Kann den Code gerne posten, auch wenn ich nicht unbedingt denke, das er weiter helfen wird. Ich versuche es so kurz wie möglich zu machen... wenn ich so manchen Code in anderen Posts sehe, trifft mich meistens der Schlag. 

Die Klasse MapDisplay.

```
public void drawVisibleMap(Graphics g) {
		// Koordinaten für parallaxen Hintergrund berechnen
		int vpx = (int)((curLevel.getWidth()-background.getWidth())/(double)(curLevel.getWidth()-parent.getViewport().getWidth()) * parent.getViewport().getViewPosition().x);
		int vpy = (int)((curLevel.getHeight()-background.getHeight())/(double)(curLevel.getHeight()-parent.getViewport().getHeight()) * parent.getViewport().getViewPosition().y);
		
		// Hintergrundbild zeichnen
		g.drawImage(background, vpx, vpy, null);
		
		// Level zeichnen
		curLevel.drawLevel(g, this);
	}
```

Die Klasse Level.

```
public void drawLevel(Graphics g, MapDisplay map) {
			Graphics2D g2d = (Graphics2D) g;
			
			// Alle Felder zeichnen
			for(int i=0; i<fields.length; i++) {	
				if(fields[i]!=null && map.isInViewport(fields[i].x, fields[i].y, fields[i].width, fields[i].height)) {
					fields[i].drawField(g);
				
					// Zeichne zusätzlich ein Raster
					if(ResCtrl.isRaster()) {
						g2d.setPaint(Color.BLACK);
						g2d.drawRect((int)fields[i].getX(), (int)fields[i].getY(), fields[i].getTile().getTileWidth(), fields[i].getTile().getTileHeight());					
					}
				}
			}
```

Die Klasse Tile. Aufruf wird von der Klasse Field durchgereicht.

```
public void drawTile(int x, int y, Graphics g) {
		for(int i=0; i<bufImgs.length; i++) {
			if(bufImgs[i]!=null) {
				// Zeichne aus einem TileSet alle 3 Layer
				if(ResCtrl.isUseVI()) {
					VolatileImage vi = ResCtrl.loadVolatileImage(bufImgs[i], bufImgs[i].getWidth(), bufImgs[i].getHeight());
					g.drawImage(vi, x, y, tileWidth, tileHeight, null);
				} else {
					g.drawImage(bufImgs[i], x, y, tileWidth, tileHeight, null);	
				}
			} 
		}
		//g.drawImage(bufMask, x, y, tileWidth, tileHeight, null); // Maske zur Kontrolle zeichnen
	}
```

Einen Full-Screen Modus möchte ich in meinem Spiel vermeiden. Das sieht das Konzept nicht vor. ;-) Im übrigen, _Repaint()_ erscheint mir etwas suspekt. Ich bekomme nämlich ab und zu so seltsame Fehlermeldungen, wenn ich den Viewport beim scrollen mit _viewport.setViewPosition(Point pos)_ neu positioniere. Ist IMO aber nicht mein Fehler. ;-) Die kehre ich einfach mit einem try-catch block unter den Teppich. Nicht die beste Methode, aber ist mir etwas zu komplex, mich da reinzuarbeiten, weil er tief in die API reingeht. Seitdem ich aber prüfe, ob das zu zeichnende Feld im sichtbereich liegt, tritt der Fehler sehr sehr selten auf. Hab gerade probiert ihn zu bekommen, aber nix. Halt sehr sporadischer Fehler.


----------



## SlippyStoat (29. Dez 2010)

Ein Keks hat gesagt.:


> Für kleine Performance-Steigerung sollte man sich die Klasse GraphicsConfiguration mal ansehen (vorallem createCompatibleImage - allerdings ist das ja auch schon in Quaxlies Tutorial drin).



Hab das im Tutorial überlesen; dachte das würde noch zu VolatileImage gehören, was ja so mit Swing Komponenten nicht funkioniert.
Mir ist nur folgendes unklar: Wieso gibt er auf Seite 134 _better_ zurück, während er auf Seite 135 _source_ weiterverwendet bzw. pics zurück gibt. Ich glaube das passt so nicht ganz.

Mich verwundert dieses Konstrukt, wie das funktionieren kann.

```
...

				BufferedImage better = gc.createCompatibleImage(src.getWidth(), src.getHeight(), Transparency.TRANSLUCENT);
				Graphics g = better.getGraphics();
				g.drawImage(source, 0, 0, null); // Wie kann diese Zeile funktionieren?
				...
```

Jetzt läufts auch mit PNG-Grafiken ruckelfrei. Allerdings verwende ich den Paramter _Transparency.TRANSLUCENT_ statt _Transparency.BITMASK_, da ich sonst kein Antialiasing hab und mir PNG ja sparen könnte. Nur noch mit VolatileImage ruckelt es, ist ja aber eh nicht transparent. Egal ob mit TRANSLUCENT oder irgend einem anderen Parameter.


----------



## Ein Keks (29. Dez 2010)

SlippyStoat hat gesagt.:
			
		

> Repaint() erscheint mir etwas suspekt. Ich bekomme nämlich ab und zu so seltsame Fehlermeldungen, wenn ich den Viewport beim scrollen mit viewport.setViewPosition(Point pos) neu positioniere.


Poste mal die Fehlermeldung, falls es noch mal auftritt.



			
				SlippyStoat hat gesagt.:
			
		

> Mir ist nur folgendes unklar: Wieso gibt er auf Seite 134 better zurück, während er auf Seite 135 source weiterverwendet bzw. pics zurück gibt. Ich glaube das passt so nicht ganz.


Da hast du allerdings recht. better wird nicht benutzt. ???:L *zu Quaxli schiel*

Bei dem Konstrukt wird erst ein komplett transparentes "kompatibles" Image erzeugt, dann holt man sich das Graphics-Object davon und malt mit diesem das "source"-bild auf das neue Bild (und eigentlich sollte man anschließend g.dispose() aufrufen).

Und wie gesagt, solang du mit swing arbeitest vergiss erstma VolatileImage - als Backbuffer wirds so oder so verwendet und für normale Bilder ist BufferedImage um einiges besser geeignet (und nebenbei einfacher da sie nicht einfach mal so verschwinden können^^).


----------



## Guybrush Threepwood (29. Dez 2010)

Ein Keks hat gesagt.:


> Und wie gesagt, solang du mit swing arbeitest vergiss erstma VolatileImage - als Backbuffer wirds so oder so verwendet und für normale Bilder ist BufferedImage um einiges besser geeignet (und nebenbei einfacher da sie nicht einfach mal so verschwinden können^^).



Eine kleine Bemerkung am Rande: Ein Vorteil von VolatileImage ist, dass man keinen Heap im normalen Arbeitsspeicher braucht.


----------



## Quaxli (29. Dez 2010)

Ein Keks hat gesagt.:


> ...
> Da hast du allerdings recht. better wird nicht benutzt. ???:L *zu Quaxli schiel*



Hoppla. Da ist wohl noch ein Fehler drinne. :shock:


----------



## SlippyStoat (3. Jan 2011)

Bzgl. dem oben erwähnten Fehler bei der Methode setViewPosition(Point p) trat immer eine ClassCastException auf. Kam bis jetzt aber wirklich nicht mehr, weshalb auch immer. Sicherheitshalber lasse ich den try-catch Block trotzdem bestehen.

Hätte trotzdem noch eine Frage zu der suspekten repaint() Methode. Beispielsweise möchte ich Icons in ein JLabel hinzufügen, wenn Items aufgesammelt werden. Oder nach Laden eines neuen LevelSets soll das Menü mit der Levelauswahl neu generiert werden. Oder wenn der Spieler nach allen Levels sich in die Rangliste möchte, so wird beim Anzeigen des Dialogs ein Textfeld erzeugt und nach der Bestätigung mit Enter soll dieses in ein Labelfeld umgewandelt werden. Das alles funktioniert nicht, weder mit repaint() noch revalidate(). Hab Google wirklich danach bemüht, aber keine Lösung dazu gefunden. Vielleicht wisst ihr eine Lösung? Echt komisch, dass das nicht funktioniert.

Ich poste hier mal den Code für den Bestenlistendialog.

```
package data.dialogs;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.Box;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

@SuppressWarnings("serial")
public class HallOfFame extends JDialog {
	
	private static final int rows=10;
	private static final int width=300;
	private JTextField tfName;
	private int newPoints;
	private static final String path="hof.csv";
	private List<Entry> list;
	
	public HallOfFame(JFrame owner, int points) {
		super(owner, "Hall Of Fame", true);
		
		list = new ArrayList<Entry>(rows); 

		FileReader fr = null;
		BufferedReader br = null;
		
		// Daten einlesen 
		try {
			fr = new FileReader(path);
			br = new BufferedReader(fr);
			
			String line = null;
			String[] split;
			
			// Jede Zeile abarbeiten
			while ((line = br.readLine()) != null) {
				if(line.contains(";")) {
					split = line.split(";");
					Entry e = new Entry(split[0], Integer.parseInt(split[1]));
					list.add(e);						
				}
			} 				
		} catch(IOException e) {
			e.printStackTrace();
		}
		
		finally { 
    		try { 
    			if (br != null) { 
    				br.close(); 
    				fr.close();
    			} 
    		}  
    		catch (IOException ex) { 
    			ex.printStackTrace(); 
    		}
		}
		

		Collections.sort(list);

		newPoints = points;
		
        // Aufbau des Design
		JPanel contentPane = (JPanel) getContentPane(); 
        contentPane.add(showList());
        
        pack();
        setLocation(owner.getLocation().x+(owner.getWidth()/2)-(this.getWidth()/2), owner.getLocation().y+(owner.getHeight()/2)-(this.getHeight()/2));
        setVisible(true);
	}
	
	private JPanel showList() {
		JPanel panContent = new JPanel();
		panContent.setLayout(new GridBagLayout());
		        
		panContent.add(Box.createRigidArea(new Dimension(width,10)), setGbcVals(0,0,5,1));
        JLabel caption = new JLabel("<html><font size='+2'>Bestenliste</font></html>", JLabel.CENTER);
        panContent.add(caption, setGbcVals(0,1,5,1));
        panContent.add(Box.createRigidArea(new Dimension(width,1)), setGbcVals(0,2,5,1,1,0.01));

        panContent.add(Box.createRigidArea(new Dimension(10,20)), setGbcVals(0,1,1,rows,0.01,1));
        panContent.add(Box.createRigidArea(new Dimension(10,20)), setGbcVals(4,2,1,rows,0.01,1));
        
        int set=0;
        for(int i=0; i<rows; i++) {
        	panContent.add(new JLabel(Integer.toString(i+1), JLabel.RIGHT), setGbcVals(1,i+3,1,1,0.1,1));
        	if(newPoints<list.get(i).getPoints() || set>0) {
        		panContent.add(new JLabel(list.get(i-set).toString(), JLabel.LEFT), setGbcVals(2,i+3,1,1));
        		panContent.add(new JLabel(Integer.toString(list.get(i-set).getPoints()), JLabel.LEFT), setGbcVals(3,i+3,1,1,0.1,1));
        	} else {
        		set=1;
        		tfName = new JTextField(8);
        		tfName.setBackground(this.getBackground());
        		tfName.addKeyListener(new KeyAdapter() {
        			public void keyPressed(KeyEvent ke) {
        				if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
        					addNewEntry();
        				}
        			}
        		});
        		panContent.add(tfName, setGbcVals(2,i+3,1,1));
        		panContent.add(new JLabel(Integer.toString(newPoints), JLabel.LEFT), setGbcVals(3,i+3,1,1,0.1,1));
        	}
        }
        
        panContent.add(Box.createRigidArea(new Dimension(width,10)), setGbcVals(0,rows+3,5,1));

		return panContent;
	}
	
	private void addNewEntry() {
		FileWriter fw = null;
		BufferedWriter bw = null;
		
		list.add(new Entry(tfName.getText(), newPoints));
		Collections.sort(list);
		
		try {
			fw = new FileWriter(path);
			bw = new BufferedWriter(fw);
			
			for(Entry e:list) {
				bw.write(e.toString()+";"+e.getPoints());
				bw.newLine();
			}
			
		} catch (FileNotFoundException ex) { //Überflüssig - Wenn Datei nicht vorhanden ist, wird sie erstellt
        	//ex.printStackTrace(); 
        	JOptionPane.showMessageDialog(getParent(), "Datei für Bestenliste nicht gefunden!\n\n"+ex.getMessage());
		} catch(IOException e) {
			JOptionPane.showMessageDialog(getParent(), "Fehler beim Schreiben der Datei!");
			e.printStackTrace();
		}
		
		finally { 
    		try { 
    			if (bw != null) { 
    				bw.flush(); 
    				bw.close(); 
    				fw.close();
    			} 
    		}  
    		catch (IOException ex) { 
    			ex.printStackTrace(); 
    		}
		}
		
		// contentPane=null; 	// funktioniert nicht
		// contentPane.revalidate(); // funktioniert nicht
		setVisible(false);
		//dialogInit();
		//this.update(this.getGraphics());
		//repaint(10,0,0,this.getWidth(),this.getHeight());			// funktioniert nicht
		//Main.putScore(0); 			// nicht die schönste Lösung
	}
	
		private GridBagConstraints setGbcVals(int x, int y, int w, int h, double wx, double wy) {
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.gridwidth = w;
        gbc.gridheight = h;
        gbc.weightx = wx;
        gbc.weighty = wy;
        gbc.fill = GridBagConstraints.NONE; 
        gbc.ipadx = 18;
        gbc.ipady = 6;
        
        return gbc;    
    }
	private GridBagConstraints setGbcVals(int x, int y, int w, int h) {
		return setGbcVals(x,y,w,h,1,1);
	}
	
	// [url=http://www.i-coding.de/www/de/java/liste/sortieren.html]Java Liste : Sortieren[/url]
	class Entry implements Comparable<Entry> {

		private String name;
		private int points;
		
		public Entry(String n, int p) {
			name = n;
			points = p;
		}
		
		@Override
		public int compareTo(Entry obj) {
			if (getPoints() < obj.getPoints()) 
				return 1; 
			else if (getPoints() == obj.getPoints()) 
				return 0; 
			else 
				return -1; 
		}
		
		public String toString() {
			return name;
		}
		
		public int getPoints() {
			return points;
		}
	}
}
```


----------



## Marco13 (3. Jan 2011)

Fehlt da viel zu einem KSKB?


----------



## SlippyStoat (6. Jan 2011)

Sorry, dauert noch a weng. Das Programmieren hat soviel Spaß gemacht, dass ich meine anderen Studienarbeiten ziemlich vernachlässigt habe, beispielsweise Software Engineering.

Kann und möchte im Moment nicht alles online stellen, weil ich Sounds und Bilder verwende, die evtl. kopiergeschützt sein könnten, da ich ne menge Material nur gegoogelt hab. Spätestens nach den Klausuren würde ich mich wieder darum kümmern.


----------

