# Dateizugriff mit Applets und RMI



## L-ectron-X (24. Nov 2004)

abollm, bitte erkläre mir doch mal, wie das funktioniert.
Welche Hindernisse gibts? Was muss beachtet werden? Und etwas einfacher Beispielcode wäre schön.
Ursprungsthread: http://www.java-forum.org/de/viewtopic.php?t=10483
Falls das Thema besser in _Netzwerkprogrammierung mit Java_ aufgehoben wäre, sagt bescheid, dann verschiebe ich's.


----------



## abollm (26. Nov 2004)

Also zunächst einmal einige kurze Erläuterungen zum Vorgehen meinerseits mit dem 
Ziel, das Thema insgesamt einerseits noch halbwegs verständlich zu lassen aber 
andererseits hier auch keine allzu langen Erläuterungen folgen zu lassen.

- Ich denke, wir sollten das Thema zunächst in diesem Thread belassen, weil wir 
ja schließlich das Lesen und Abspeichern von Daten mittels Applet umreißen 
(werden).

- Allein das Thema RMI kann einen schon reichlich Zeit kosten, wenn man a) nicht 
genügend Grundverständnis für die Zusammenhänge von RMI (=Remote Method 
Invocation) aufbringt bzw. b) sich nicht wenigstens einigermaßen mit den 
Grundlagen beschäftigt hat. Die Anzahl der Fehlermöglichkeiten kann bei diesem 
Thema nämlich recht schnell anwachsen (ich spreche da auch aus eigener 
Erfahrung).

- Folgende Dinge im Zusammenhang mit RMI sollte man _grundsätzlich_ verstanden 
haben (Lit. hierzu gibt es reichlich im I-Net):

1. Die grundlegende Arbeitsweise von RMI

2. Die wesentlichen Aspekte der Kommunikation zwischen Stubs und Skeletons

3. Registrieren der Objekte mittels rmiregistry

4. Umgang mit Policy-Dateien

- Ich baue ein Beispiel zum Thema schrittweise auf, auch weil ich den Code nicht 
mal eben so aus "dem Ärmel schütteln kann", da die von mir entwickelte Vorlage 
u.a. viel zu komplex wäre, sie hier zu posten (> 12000 Zeilen). Mein Vorschlag 
wäre, per Applet aus einer Mini-JTable (50 Zeilen und 26 Spalten) Daten sowohl 
auf den Server schreiben als auch Server-Daten in diese einlesen zu können. Das 
hätte den Vorteil, auch das "beliebte" Thema JTable gleichzeitig praktisch hier 
einbinden zu können.

Aber wir könnten auch ein anderes Beispiel nehmen, da bin ich grundsätzlich 
flexibel, erwarte dann aber auch Hilfeleistung durch andere.

Und schließlich noch Folgendes: 

Keiner ist fehlerfrei, ich natürlich auch nicht. Anregungen, Korrekturen, 
Ergänzungen sind ausdrücklich erwünscht.

Vermutlich morgen geht's aus meiner Sicht dann weiter.


----------



## L-ectron-X (26. Nov 2004)

Klasse abollm, bin schon gespannt, wie ein Flitzebogen. :wink:


----------



## abollm (29. Nov 2004)

Leider hat sich die Umstellung meines "Beispiels" doch langwieriger als erwartet herausgestellt.

Grundsätzlich funktioniert das Bsp. zwar, allerdings gibts beim Speichern noch Fehlermeldungen, die ich ausbauen muss. Nur zur Info: die Gesamtzahl der Zeilen Code beträgt auch jetzt noch mehrere tausend.

Zum weiteren Ablauf.:

Wenn das Beispiel voll funktioniert, stelle ich es zunächst per Jar-Datei zur Verfügung. Den Quelltext der HTML-Datei poste ich hier. Außerdem gebe ich dann konkrete Hinweise zur korrekten Bedienung des Beispiels, also wie die einzelnen Komponenten anzusprechen sind, damit man mit dem Applet Dateien laden und speichern kann.


----------



## abollm (5. Dez 2004)

So, nun habe ich das Applet für eine erste Demo fertig. Du, oder auch andere 
Interessierte können es von folgender Adresse herunterladen:

http://home.arcor.de/bollm/MyJTable/

In diesem Ordner befinden sich zwei Dateien:

1. HTM.ZIP
2. MyJTableApplet.jar

Zum Herunterladen vom Web-Server musst du einen Nutzernamen und ein zugehöriges 
Kennwort eingeben:

Nutzer:   mjt
Passwort: Dein Nick-Name (L-...)

Bitte auf eine exakte Schreibweise achten!

(Übrigens: Bitte nicht unnötig lange den Web-Server-Ordner blockieren, d.h. offen 
lassen, da Arcor zurzeit wohl nur maximal zwei Verbindungen zur gleichen Zeit 
zulässt!)

Die in den Archiven enthaltenen Dateien bitte in einen beliebigen Ordner 
auf deiner Maschine entpacken.

Im ZIP-Archiv zu 1. ist die eigentliche HTML-Datei "MyJTable.html" sowie das 
zugehörige Hintergrund-Bild.

Im JAR-Archiv zu 2. sind alle notwendigen Klassen zum Betrieb des Applets und des 
Server-Dienstes enthalten.

Zum Starten des Servers und des Applets sind folgende Schritte notwendig:

1.Starten der RMI-Registry (unter Windows muss das "start"-Kommando benutzt 
  werden:
  start rmiregistry

  (unter LINUX/UNIX habe ich zwar nicht getestet, aber hier muss "rmiregistry &" 
  eingegeben werden)

2.Starten des RMI-Servers (unter Windows muss das "start"-Kommando benutzt 
  werden:
  start java MyJTableServer

  (unter LINUX/UNIX benutze das Kommando "java MyJTableServer &")

  An dieser Stelle sollte auf dem Bildschirm eine Meldung wie folgt erscheinen:
  Erzeuge MyJTable-Server-Ausfuehrung...
  Binde Server-Ausfuehrung in die Registry...
  ...
  Warte auf Client-Anforderungen...

  Nur in diesem Fall war das Binden der Registry erfolgreich. Man kann das auch 
  noch durch folgenden Aufruf überprüfen:
  java ShowBindings

  Danach sollte folgende Ausgabe erfolgen:
  "//:1099/MyJTableServer"

  oder

  "rmi://:1099/MyJTableServer" 

3.Öffne den Web-Browser und lade die HTML-Seite.

Wenn anschließend keine Warn-Meldung erscheint, dann hast du erfolgreich den 
Server-Dienst gestartet. Nun kannst du mit dem Applet auf deiner Maschine (in 
diesem Fall ist deine Maschine Client und Server zugleich) Dateien laden und 
speichern.

Das Applet selbst ist zurzeit nur in einem "absoluten Demo-Stadium". Wie du 
(hoffentlich) erkennen wirst, sind in der Tabelle alle Spalten der ersten zwei 
Tabellenzeilen mit JCombo-Boxen belegt. _Nur_ diese Werte werden zurzeit geladen 
und abgespeichert (also die sonstigen Zellenwerte bleiben unberücksichtigt). Dazu 
werden Dateien (ASCII-Format) mit Zahlenwertangaben, die den jeweiligen Eintrag 
der JCombo-Boxen repräsentieren, angelegt. In dieser Datei wird zusätzlich noch 
der so genannte ID-Wert (siehe Applet) gespeichert.

Randbedingungen:
Entwicklung:
Mit Java 1.5 unter
Windows 2000 Professional

JTable:
26 Spalten (davon die ersten zwei jeweils mit JCombo-Boxen belegt) und
50 Zeilen

Ich schlage vor, dass du bzw. alle sonstigen Interessierten sich zunächst mit dem 
Applet kurz vertraut machen und wir anschließend das Applet gemeinsam so 
erweitern, damit die dahinter stehende Technik klar wird.

Dann gibt es auch ein "wenig" Java-Code.


----------



## L-ectron-X (5. Dez 2004)

OK, danke erst mal! Ich schaue es mir an.


----------



## abollm (5. Dez 2004)

L-ectron-X hat gesagt.:
			
		

> OK, danke erst mal! Ich schaue es mir an.



Ich hatte eben (vor ca. 20 Min.) noch einen Fehler wg. Zugriff auf die Seite entdeckt. Jetzt müsste der Zugriff klappen.


----------



## !abollm (12. Dez 2004)

Mittlerweile habe ich eine vervollständigte Version des Applets (Jar-Datei) 
fertig und auf dem o.a. Link abgeladen.

Mit dem Applet können nun auch die eigentlichen "Nutzdaten" in der Tabelle 
gespeichert und geladen werden. Diese so genannten Nutzdaten, d.h. die Daten ab 
der dritten Zeile der JTable werden im CSV-Format mit Semikolon als Trennzeichen 
und den Anführungszeichen als Quotierungszeichen gespeichert. Daraus ergeben sich 
zwangsläufig gewisse Restriktionen beim Eingeben der Daten, die zu beachten sind.

Nun zum Aufbau und dem Zusammenspiel:

Die folgenden Klassen sind die wichtigsten für den Betrieb des per RMI 
aufgerufenen Applets:

1. MyJTableServer
2. MyJTableExchange
3. MyJTableImpl
4. MyJTableApplet

Zu 1.:
Enthält folgenden Code:

```
import java.rmi.*;

/** Server-Applikation */
public class MyJTableServer {
/** 
 *  Mit Hilfe von RMI wird registriert und eine Instanz der Klasse MyJTableImpl 
 *  gestartet; anschließend wird auf Client-Anforderungen gewartet. 
 */
public static void main(String args[]) {
	try {
		System.out.println("Erzeuge MyJTable-Server-Ausfuehrung...");
		MyJTableImpl j = new MyJTableImpl();
		
		System.out.println("Binde Server-Ausfuehrung in die Registry...");
	
		Naming.bind(MyJTableImpl.SERVER_NAME, j);
		Naming.rebind(MyJTableImpl.SERVER_NAME, j);
		
		System.out.println("Warte auf Client-Anforderungen...");
	}
	catch(Exception e) {
		System.out.println("Fehler: " + e);
	}
}
}
```
Die Methode "main" läuft, wenn der Serverdienst gestartet ist (s.o.). Diese 
Methode erzeugt eine Instanz der Klasse "MyJTableImpl" und registriert den 
Server mittels RMI-Registry auf der Maschine des Servers.

Die im Code zu erkennende Meldung erscheint auf dem Bildschirm, wenn der 
Serverdienst erfolgreich gestartet wurde.

Zu 2.:

Diese Klasse enthält die Definitionen für MyJTable-Exchange, bildet also die 
Schnittstelle zu den serverseitigen Funktionalitäten

Zu 3.:
Das ist die Implementierung der Schnittstelle.

Zu 4.:

Initialisiert das Applet, erstellt die grafische Benutzerschnittstelle (GUI) und 
setzt alle notwendigen Listener.

So, nun kann jeder damit herumspielen und Fragen stellen.


----------



## abollm (12. Dez 2004)

Anonymous hat gesagt.:
			
		

> Mittlerweile habe ich eine vervollständigte Version des Applets (Jar-Datei)
> fertig und auf dem o.a. Link abgeladen.
> ...
> So, nun kann jeder damit herumspielen und Fragen stellen.



Ja, das war ich (mal wieder ausgeloggt).


----------



## L-ectron-X (12. Dez 2004)

Klasse! Ich habe mir erst mal die Dateien von Deinem Space gezogen und schaue mir das an, so bald ich Zeit habe.
Da kommen sicher noch Fragen...


----------



## 8ull23y3 (13. Dez 2004)

http://www.java-forum.org/de/viewtopic.php?t=11729

keine Ahnung ob sowas gemeint ist.


----------



## abollm (14. Dez 2004)

8ull23y3 hat gesagt.:
			
		

> ...keine Ahnung ob sowas gemeint ist.



Nein, das war hier nicht gemeint. Es soll mittels Applet und RMI auf ein Verzeichnis auf Dateien (lesen und schreiben) zugegriffen werden. Diese Dateien liegen auf der Maschine (Server), auf der der mittels RMI registrierte Server-Dienst gestartet wird.

Dazu ist ein Web-Server (wie bei PHP) ausdrücklich nicht erforderlich.


----------



## 8ull23y3 (14. Dez 2004)

Hm... dann hab ichs falsch verstanden. Sorry


----------



## L-ectron-X (21. Dez 2004)

Moin abollm!
Habe nun endlich mal mir die Zeit genommen, mir das Ganze einmal näher anzuschauen.
Nach anfänglichen Problemen zunächst mal zu verstehen, wie das Ganze in Betrieb genommen wird, hat's nun geklappt und das Applet läuft. Letzendlich funktionierte es so:
Eine Batchdatei geschrieben, die den Pfad setzt und die RMIRegistry und den Server startet, Apache gestartet, und vom Web aus auf meinen Rechner zugegriffen.
Allerdings konnte ich keine Eingaben speichern, weil mir ein JOptionPane meldete, dass dies nicht möglich sei.
Auch war ich überrascht ein "echtes" JMenu zu sehen. (das hatten wir ja gerade in einem anderen Thread)
Ich habe mich bisher noch nie mit RMI und seinen Möglichkeiten beschäftigt, war aber auch ohne, dass das Speichern der Tabellendaten funktionierte von der ganzen Sache angetan.
Von der Technik habe ich nun also keine Ahnung. Wie gehts nun weiter?


----------



## abollm (21. Dez 2004)

L-ectron-X hat gesagt.:
			
		

> ...
> Nach anfänglichen Problemen zunächst mal zu verstehen, wie das Ganze in Betrieb genommen wird, hat's nun geklappt und das Applet läuft. Letzendlich funktionierte es so:
> Eine Batchdatei geschrieben, die den Pfad setzt und die RMIRegistry und den Server startet, Apache gestartet, und vom Web aus auf meinen Rechner zugegriffen.
> Allerdings konnte ich keine Eingaben speichern, weil mir ein JOptionPane meldete, dass dies nicht möglich sei.
> ...



Ja, wie geht es bei den Möglichkeiten von RMI und der damit zusammenhängenden Fülle von Stoff weiter, wenn ich das man selbst wüsste?

Bevor ich zu meinen Vorschlägen komme, einmal eine Frage: Wieso hast du einen Web-Server gestartet? Wenn RMI via RMIregistry zusammen mit dem Server-Dienst (-> MyJTableServer) richtig gestartet wurde (s. Anleitung oben), dann kanst du via Netzwerk auch ohne Webserver auf das Applet zugreifen und Dateien laden und speichern. Ich weiß allerdings selbst aus eigener Erfahrung, dass bis zum fehlerfreien Laufen eines RMI-Server-Dienstes einige Stunden Arbeit notwendig sein _können_ (nicht müssen).

Das mit der Batch-Datei ist in Ordnung, so mache ich das auch. Das erspart im Regelfall viel Ärger, da man die Pfade so  individuell und einfach setzen kann. Hier einmal ein Beispiel meiner Batch-Datei auf meinem W2K-System:

```
@REM Start RMIregistry
@start C:\Programme\Java\jre1.5.0\bin\rmiregistry 1099
@REM Start Server-Dienst
@rem start C:\Programme\Java\jre1.5.0\bin\java MyJTableServer
```

Vielleicht einmal folgender Vorschlag:

Du versuchst, die ganze Applikation (Server und Applet) einmal _ohne_ Web-Server so auf deiner Maschine zum Laufen zu bringen, dass du auf dieser (sie ist dann zugleich Client und Server) auch direkt das Applet, inklusive der Möglichkeit Dateien laden und speichern zu können, zum Laufen bringst. Einverstanden? 

Ich werde in der Zwischenzeit die wichtigsten weiteren Code-Fragmente zusammenstellen und diese hier dann in einem weiteren Beiztrag zusammen mit wichtigen Kommentaren posten.

Dann sehen wir weiter.


----------



## L-ectron-X (22. Dez 2004)

Den Webserver habe ich gestartet um "Realbedingungen" zu schaffen. Applets sind im Internet zuhause, also teste ich sie auch immer über das Netz.
In Deiner Batchdatei ist mir aufgefallen, dass Du der rmiregistry einen Port als Argument übergeben hast. Das habe ich wohl übersehen. Möglicherweise ist dort auch der Grund für das Nichtspeichern zu suchen.
Ich probiere das Ganze noch mal wie gehabt mit Port, dann werden wir sehen. Sollte das nicht funktionieren, folge ich Deinem Rat, ansonsten habe ich meinen Fehler schon gefunden.

Ich freue mich auf Deinen nächsten Post.


----------



## abollm (31. Jan 2005)

Wollen wir die Tage weitermachen mit dem Thema?

Ich schlage vor, dass ich den wichtigsten Code zum obigen Beispiel kommentiert poste. Dann sehen wir weiter.


----------



## L-ectron-X (11. Feb 2005)

Ich habe es nochmal getestet, diesmal mit Angabe eines Ports. Funktionierte super!
Zu Deiner Frage: Klar. Weiter geht's!


----------



## abollm (14. Feb 2005)

L-ectron-X hat gesagt.:
			
		

> Ich habe es nochmal getestet, diesmal mit Angabe eines Ports. Funktionierte super!
> Zu Deiner Frage: Klar. Weiter geht's!


Das freut mich ja, dass es einwandfrei funktioniert hat.

Weiter oben hatte ich bereits einmal die wichtigsten Klassen (den Quelltext der Klasse MyJTableServer hatte ich dabei gepostet) erwähnt, deshalb hier zunächst die komplette Liste aller Klassen (ohne bestimmte Reihenfolge, aber mit kurzen Erläuterungen):

1.  ColorizedCell - Erweiterung DefaultTableCellRenderer
2.  DebugInfo - Für Debugging-Zwecke
3.  LoadDialog - lade Dialog für Dateiauswahl
4.  MyComboBoxRenderer -  Erweiterung BasicComboBoxRenderer
5.  MyJTableApplet -  Applet für MyJTable
6.  MyJTableExchange - Schnittstelle zum Server mit entspr. Methoden
7.  MyJTableFilenameFilter - Einrichtung des FilenameFilter-Interface
8.  MyJTableAppletImpl - Implementierung der MyJTableApplet-Schnittstelle
9.  MyJTableModel - Erweiterung DefaultTableModel
10. MyJTableServer - Server-Applikation für die MyJTable-Anwendung mit Hilfe von RMI (Remote Method Invocation)
11. MyJTableTable - Klasse mit Methoden, um die Daten für die Tabelle zu speichern/ändern
12. RowEditorModel -  Datenmodell für die Tabelle mit den Initialisierungsdaten. (die ersten zwei Zeilen der JTable)
13. SaveAsDialog - Die so genannte Dialog-Box für das Speichern
14. ShowBindings - Zeige Bindungen

Der Code zu 1.:


```
/**
 * Projekttitel:  MyJTableApplet
 * Project title:
 * Beschreibung:  
 * Description:   
 * Copyright:     Copyright (c) 2002-2004
  * Company:
 * Modul:         ColorizedCell
 * Beschreibung:  
 * Description:   
 * @author        ABollm - München
 * @version       0.9.0.2
 * Historie /
 * history:       0.9.0.1 - erste Testversion / first testing version
 *                0.9.0.2 - Farben erweitert
 */
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

class ColorizedCell extends DefaultTableCellRenderer {

  static Hashtable cache;

  static {
    cache = new Hashtable();
    cache.put ("white",Color.white);
    cache.put ("lightGray",Color.lightGray);
    cache.put ("gray",Color.gray);
    cache.put ("darkGray",Color.darkGray);
    cache.put ("black",Color.black);
    cache.put ("red",Color.red);
    cache.put ("pink",Color.pink);
    cache.put ("orange",Color.orange);
    cache.put ("yellow",Color.yellow);
    cache.put ("green",Color.green);
    cache.put ("magenta",Color.magenta);
    cache.put ("cyan",Color.cyan);
    cache.put ("blue",Color.blue);
    cache.put ("ultraLightGray",Color.RGBtoHSB(100,100,100,null));
  }

  protected void setValue(Object value) {
    if (value != null) {
      Color c;
      c = (Color)cache.get (value);
      if (c == null)
        c = Color.black;

      Icon icon = new ColorizedIcon (c);
      setIcon (icon);
    }
  }

  static class ColorizedIcon implements Icon {
    Color color;
    public ColorizedIcon (Color c) {
      color = c;
    }
    public void paintIcon (Component c, Graphics g, int x, int y) {
      int width = getIconWidth();
      int height = getIconHeight();
      g.setColor (color);
      g.fillOval (x, y, width, height);
    }
    public int getIconWidth() {
      return 10;
    }
    public int getIconHeight() { 
      return 10;
    }
  }
}
```

Der Code zu 2.:

```
/**
 * Projekttitel:  MyJTableApplet
 * Project title:
 * Beschreibung:  
 * Description:  
 * Copyright:     Copyright (c) 2002-2004
 * Unternehmen:   
 * Company:
 * Modul:         DebugInfo
 * Beschreibung   Wird von den MyJTable-Modulen benutzt, um Informationen 
 *                (zwecks Debugging, Logging etc.) zur Laufzeit anzuzeigen. 
 *                Weitere Informationen siehe unten.
 * Description:   
 * @author        ABollm - München
 * @author        
 * @version       0.9.0.2
 * history
 *
 */

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class DebugInfo extends JFrame implements ActionListener {
	// Größenparameter für Debug-Informationsfenster
	private static final int width = 600;
	private static final int height = 500;
	
	// Parameter für Debug-Informations-Komponente
	private JScrollPane jsp;
	private JTextArea jta;
	private JButton jbClear;
	private Container contentPane;
	
	public DebugInfo() {
		setTitle("Informationen für Debug-Zwecke");
		setSize(width,height);
		setLocation(0,0);
		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent we) {
				setVisible(false);
			}
		}); 
		
		// Hole 'contentpane' für den Rahmen
		contentPane = getContentPane();

		jta = new JTextArea();
		jta.setEditable(false);
		jsp = new JScrollPane(jta);
		jbClear = new JButton("Lösche");
		jbClear.addActionListener(this);
	
		// Füge Komponenten zum Debug-Dialog hinzu
		contentPane.add(jsp,"Center");  // Constraints so lassen!
		contentPane.add(jbClear,"South"); // -------- " ---------
	}
	
	public void displayWindow() {
		setVisible(true);
	}

	public void appendMessage(String s) {
		jta.append(s);
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource()==jbClear) {
			jta.setText("");
		}
	}
}
```

Code zu 3.

```
/**
 * Titel:         MyJTableApplet
 * Title:
 * Beschreibung:  
 * Description:   
 * Copyright:     Copyright (c) 2002-2004
 * Unternehmen:   
 * Company:
 * Modul:         Lade Datei - Dialog Box
 * Description:   Dialog box für die Lade-Datei-Funktion
 * @author        ABollm
 * @author        
 * @version       0.9.0.2 - 09.12.2002
 * Last update: 
 *              	- Dialogbox nicht in der Größe veränderbar eingestellt, Scollbar stets angezeigt.
 *              	- Ab jetzt eine neue Methode, sodass der Dialog auf dem Applet stehen bleibt.
 *              	- Popup-Meldung auskommentiert, da es dazu führte, dass Dialog Modalität verlor.
 */

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
//import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
//import java.lang.*;
//import java.util.*;


/** Dies ist die Dialog-Box zum Laden von .MJT-Dateien  */
public class LoadDialog extends JOptionPane implements ActionListener,
    ListSelectionListener, KeyListener {
	// Größenparameter der Komponenten.
	private static final int width = 400;
	private static final int height = 365;
	private static final int labelHeight = 25;
	private static final int buttonHeight = 25;
	private static final int buttonWidth = 100; //alt: 90
	private static final int innerMargin = 10;
	private static final int innerWidth = 373;
	private static final int jspHeight = 220;

	// Positionsparameter der Komponenten.
	private static final int jlbX1 = innerMargin;
	private static final int jlbY1 = innerMargin;
	private static final int jlbX2 = innerWidth;
	private static final int jlbY2 = labelHeight;

	private static final int jspX1 = innerMargin;
	private static final int jspY1 = innerMargin+labelHeight+1;
	private static final int jspX2 = innerWidth;
	private static final int jspY2 = jspHeight;
	
	private static final int jbRetrieveX1 = innerMargin+90;
	private static final int jbRetrieveY1 = jspY1+jspHeight+10;
	private static final int jbRetrieveX2 = buttonWidth;
	private static final int jbRetrieveY2 = buttonHeight;

	private static final int jbCancelX1 = jbRetrieveX1+buttonWidth+11;
	private static final int jbCancelY1 = jbRetrieveY1;
	private static final int jbCancelX2 = buttonWidth;
	private static final int jbCancelY2 = buttonHeight;
	
	// Schnittstellen-Komponenten
	
	private JTextField jtf;

	
	private JList filelist;
	private JScrollPane jsp;
	private JLabel jlb;
	private JButton jbRetrieve;
	private JButton jbCancel;
	private JDialog dialog;
	private Container contentPane;
	
	private boolean cancelled = false;

	/** 
	 * Konstruktor, der einen neuen Datei-Laden-Dialog erstellt.
	 * @param names  Ein String-Array, das die Dateinamen der bereits 
	 *               auf dem Server gespeichterten Dateien enthält.
	 */
	public LoadDialog(Component parent, String[] names) {
		super();
		dialog = createDialog(parent, "Lade...");
		dialog.getContentPane().removeAll();
		dialog.setSize(width,height);
		dialog.setResizable(true); // vorher: false
/*		//Zentriere die Dialogbox auf dem Bildschirm
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		int x = (screenSize.width - width) / 2;
		int y = (screenSize.height - height) / 2; */
		// Die 'createDialog'-Methode hat eine kleine zentrierte Dialogbox auf dem 
		// Applet erstellt. Nachdem der Dialog vergrößert wurde, müssen wir ihn verschieben.
		int x = (int)dialog.getLocation().getX() - 70;
		int y = (int)dialog.getLocation().getY() - 130;
		dialog.setLocation(x,y); 
		dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		dialog.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent we) {
				cancelled = true;
				dialog.setVisible(false);
			}
		}); 
		
		// Hole Inhaltsleiste für den Dialog
		contentPane = dialog.getContentPane();

		// Initialisiere Dateiliste und andere Schittstellenkomponenten.
		try{
			filelist = new JList(names);
		}catch(Exception e) {
			filelist = new JList();
		}
		filelist.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		jsp = new JScrollPane(filelist);
		jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		jlb = new JLabel("Wählen Sie eine Datei aus: ");
		jbRetrieve = new JButton("Laden");
		jbCancel = new JButton("Abbruch");
		jbRetrieve.addActionListener(this);
		jbCancel.addActionListener(this);
	
		// Benutze absolute Koordinaten im Layout anstelle eines Layout-Managers
		contentPane.setLayout(null);
		jsp.setBounds(jspX1,jspY1,jspX2,jspY2);
		jbRetrieve.setBounds(jbRetrieveX1,jbRetrieveY1,jbRetrieveX2,jbRetrieveY2);
		jbCancel.setBounds(jbCancelX1,jbCancelY1,jbCancelX2,jbCancelY2);
		jlb.setBounds(jlbX1,jlbY1,jlbX2,jlbY2);
		
		// Füge Komponenten zum Dialog hinzu
		contentPane.add(jsp);
		contentPane.add(jbRetrieve);
		contentPane.add(jbCancel);
		contentPane.add(jlb);
		
		dialog.setVisible(false);
	}
	
	/** Zeigt den Dialog an, der zuerst unsichtbar ist, wenn er konstruiert wird. */
	public void displayDialog() {
		dialog.setVisible(true);
	}
	
	/** Gibt den Dateinamen der aus der Dateiliste gewählten Datei aus. */
	public String getFilename() {
		if (cancelled) return null;
		else return (String)filelist.getSelectedValue();
	}

	//public void getTextFieldInput() {
	private void getTextFieldInput() {
		if (jtf.getText() != null && !jtf.getText().trim().equals(""))
			dialog.setVisible(false);
		//		else
		//			JOptionPane.showMessageDialog(contentPane, "Bitte geben Sie zuerst
		// einen Dateinamen ein.", "Speichern als...",
		// JOptionPane.INFORMATION_MESSAGE);
	}

	
/*
 *  Methoden für den ActionListener ------------------------------------------
 */
	/** Führe geeignete Aktionen aus, wenn ein Knopf geklickt wird. */
    public void actionPerformed(ActionEvent ae) {
    	// Wenn Anwender 'Laden' gedrückt hat
		if (ae.getSource() == jbRetrieve) {
			if (filelist.getSelectedValue() != null)
				dialog.setVisible(false);
//			else
//				JOptionPane.showMessageDialog(contentPane, "Bitte zuerst eine Datei auswählen.", "Lade Datei...", JOptionPane.INFORMATION_MESSAGE);
		}
		// Wenn Anwender 'Abbruch' gewählt hat.
		else if (ae.getSource() == jbCancel) {
			cancelled = true;
			dialog.setVisible(false);
		}
	}
    
	/*
	 * Methode für den ListSelectionListener -----------------------------------
	 */
	/** Wenn Auswahl aus der Liste, Text in Eingabe aktualisieren. */
	public void valueChanged(ListSelectionEvent e) {
		jtf.setText((String) filelist.getSelectedValue());
	}

    
	/*
	 * Methoden für den KeyListener --------------------------------------------
	 */
	/** KeyListener. Leere Methode. */
	public void keyTyped(KeyEvent e) {
	}

	public void keyPressed(KeyEvent e) {
	}

	/** Hört auf 'keyReleased'-Ereignis im Text-Feld. */
	public void keyReleased(KeyEvent e) {
		// KeyListener ist nur mit Textfeld verbunden, deshalb
		// braucht die Herkunft des KeyEvent hier nicht geprüft werden
		if (e.getKeyCode() == 10) { // Falls ENTER-Taste gedrückt wurde
			getTextFieldInput();
		}
	}
}
```

Und der Code zu 4.:

```
/**
 * Projekttitel:  MyJTableApplet
 * Project title:
 * Beschreibung:  
 * Description:   
 * Copyright:     Copyright (c) 2002-2004
 * Company:
 * Modul:         MyComboBoxRenderer
 * Beschreibung:  
 * 
 * Description:   
 * @author        ABollm - München
 * @version       0.9.0.5
 * Historie /
 * history:       0.9.0.1 - erste Testversion / first testing version
 */
import java.awt.Component;

import javax.swing.JList;
import javax.swing.JSeparator;
import javax.swing.ListCellRenderer;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public  class MyComboBoxRenderer extends BasicComboBoxRenderer implements ListCellRenderer {
  JSeparator separator;

  public MyComboBoxRenderer() {
    setOpaque(true);
    setBorder(new EmptyBorder(1, 1, 1, 1));
    separator = new JSeparator(JSeparator.HORIZONTAL);
  }

  public Component getListCellRendererComponent( JList list, 
         Object value, int index, boolean isSelected, boolean cellHasFocus) {
    String str = (value == null) ? "---" : value.toString();
    if (MyJTableApplet.SEPARATOR.equals(str)) {
      return separator;
    }
    if(isSelected) {
       setBackground(list.getSelectionBackground());
       setForeground(list.getSelectionForeground());
       if (-1 < index) {
//           list.setToolTipText(bTableTooltips[index]);
//Achtung ! - Aktivieren obiger Zeile führt momentan dazu, dass JComboBox für Zeile 0 nicht nach unten
//aufklappt, Lösung derzeit nicht in Sicht.
       }
    } else {
       setBackground(list.getBackground());
       setForeground(list.getForeground());
    } 
    setFont(list.getFont());
    setText((value == null) ? "" : value.toString());     
    setText(str);
    return this;
  }  
}
```

Die Tage geht es dann weiter.


----------



## L-ectron-X (23. Feb 2005)

Danke für Deine Mühe. Bin im Moment ziemlich eingespannt. Arbeit, Familie etc. 
Ich schaue mir Deinen Code an. :toll: Wenn ich durch bin, oder Fragen habe hörst Du von mir.


----------



## Gast (14. Nov 2006)

Hi!

Kommt denn der Code für die anderen Klassen auch noch?


----------

