Ich hatte in letzter Zeit öfter mit der Installation von Windows 7 auf älteren Computern zu tun. Damit meine ich Computer mit 1,6GHz Single Core, 1GB RAM, onboard Grafik und einer 40GB Festplatte.
Hier zusammengefasst ein paar Tipps & Tricks, die bei der Installation und Optimierung eines Windows 7 auf solchen Uralt-PCs helfen.

Wie viel Platz braucht Windows 7?
Je nach Version (Starter, Home, Pro, Enterprise) und je nach Architektur (32, 64) benötigt eine blanke Installation von Windows zwischen 4GB und 9GB Speicherplatz. Hinzu kommen die 2 Daten für die Auslagerung und den Ruhestand (pagefile und hyberfil), für gewöhnlich jeweils so groß wie der eingebaute RAM. Also ein frisch installiertes Windows 7 Home Premium 32bit mit 1,5GB RAM verbraucht etwa 7-8GB (4-5GB + 1,5GB + 1,5GB). Nun kommen noch große Datenmengen an Treibern, Windows Updates und temporären Daten hinzu. Dieses frisch installierte Windows 7 wächst von seinen 7-8GB auf 13GB allein nur durch die Installation aller Windows Updates und Service Pack 1 (Stand Feb 2013). Dazu kommen jetzt noch Treiber und Standardprogramme wie DirectX, Flash, Java, etliche Frameworks usw, die zum Betrieb aktueller Software oder Internetseiten gebraucht werden; 14-15GB für ein ausgestattetes System kann man also einplanen. Deswegen spricht Microsoft von einer Mindestanforderung von 16GB diese sind mindestens zu empfehlen. 20GB oder besser 30GB sollte die Partition fassen, wenn das System zukunftstauglich eingerichtet werden soll. Denn es folgen sicher weitere Updates, die Computerbenutzung schafft schnell neue Datenmengen, das Entpacken von Archiven benötigt ebenfalls temporären Platz auf der Systempartition.


Sollte ich alle Updates installieren?
Je nach Festplattenplatz und Nutzung des Computers empfiehlt es sich, die Windows Updates zumindest einmalig vollständig zu installieren. Updates sollen in erster Linie ja die Sicherheit und Stabilität verbessern. Aber auch wenn der Computer nicht in’s Internet gehen soll, also Sicherheit nicht so relevant ist, gibt es viele Updates die bestimmte Funktionen von Windows nachrüsten (z.B. die Erkennung von SD Karten mit mehr als 32GB) oder Voraussetzungen installieren (.NET Framework), die für den täglichen Gebrauch nützlich oder erforderlich sind.
Das Deaktivieren der Windows Updates verschafft dem PC etwas mehr Ruhe und entlastet das Netzwerk, ist aber grundsätzlich nicht zu empfehlen, da die Sicherheit des Computers stark beeinträchtigt wird.
Wenn der freie Platz der Partition zu klein wird, empfiehlt es sich die Sicherungsdateien der Updates zu löschen. Startet die „Datenträgerbereinigung“ des Systemlaufwerks und lasst die „Service Pack Sicherungsdateien“ aufräumen.


Performance-Tuning im „Leistungsinformationen- und tools“ (einfach in der Startmenü Suche eingeben):

Visuelle Effekte optimieren -> Für optimale Leistung anpassen: deaktiviert alle grafischen Spielereien, die vor allem Computer mit alter CPU und onboard Grafik in die Kniehe zwingen. Einzelne Effekte können auf Wunsch aktiviert werden, wenn man darauf Wert setzt. Zum Beispiel empfinden viele Menschen es als besonders anstrengend den Effekt „Kanten der Bildschirmschriftarten verfeinern“ zu deaktivieren. Wer nicht den kompletten Uralt Style erträgt kann auch „Visuelle Stile für Fenster und Schaltflächen“ wieder aktivieren.

Indizierungsoptionen anpassen -> Der Indizierungsdienst verbessert die Windows Suche durch das ständige Durchsuchen von Daten. Das kostet dauerhaft Leistung und hilft eher selten. Ich deaktiviere diesen Dienst auf den meisten PCs.
Entweder über „Dienste“ -> „Windows Search“ -> Beenden & Starttyp auf Deaktiviert stellen oder über die CMD mit den 2 Befehlen:

net stop wssearch
sc config wsearch start= disabled

Datenträgerbereinigung öffnen -> Wenn der PC normal läuft und auch noch einigen Neustarts wie gewünscht funktioniert kann man in der Datenträgerbereinigung einige überflüssige Daten loswerden. Am größten wird der Posten „Service Pack Sicherungsdateien“ sein, aber auch die „Temporary Internet Files“ und die Einträge der Fehlerberichterstattung können noch einige Megabyte enthalten. Lasst diese Punkt von Windows mal bereinigen. Alternativ ist auch der CCleaner ein super Tool zum Aufräumen.
Unter Windows XP gibt es im Ordner C:\Windows die berühmten $NtUninstall und $NtServicePackUninstall Ordner. Auch die können Weg um Speicher freizugeben, wenn alles läuft.


Dienste deaktivieren:
Dies ist immer ein kritischer Part, hier muss jeder selber entscheiden wie wichtig die Stabilität des Systems gegenüber dem Performancegewinn ist.

Hier eine Liste der Windows Dienste, die man (zumindest laut dem Autor des verlinkten Artikels) deaktivieren könnte: LINK.
Und noch eine Liste aller Dienste mit ihren Funktionen, empfohlenen Einstellungen und möglichen Nachteilen: LINK.

Allgemein kann man im „Dienste“ Dialog von Windows jeden Dienst erst Beenden (falls er läuft) und dann den Starttyp auf Manuell oder deaktiviert setzen.
Ich habe kaum einen Dienst deaktiviert (Windows Search, Design), kann hier also nicht viele Tipps geben. An dieser Stelle werde ich mich aber nochmal belesen und sicher ein paar Dienste wie Windows Error Reporting Service oder Windows Media Center Service Launcher nochmal überdenken. Denn außerhalb der Arbeit benötige ich viele Funktionen wirklich nicht.


Systemstart überprüfen:
Eine gute alte Möglichkeit die Leistung und vor allem den Systemstart zu erhöhen ist das Aufräumen der Autostart-Programme. Diese Programme werden automatisch mit Windows gestartet und bleiben meistens dauerhaft aktiv.

Das Tool „msconfig“ enthält den Tab „Systemstart“ und listet dort alle Programme auf, die mit Windows gestartet werden können. Alle gesetzten Haken zeigen aktive Autostarts an und sollten überprüft werden. Hier erfordert es ein wenig IT Hintergrund wissen, überflüssige Programme auszusortieren. Die Startup Application Knowledge Base verrät zur Not Informationen zu bekannteren Programmen.


Unbenötigte Windows Funktionen deaktivieren:
Viele Funktionen sind standardmäßig aktiviert, bleiben aber unbenutzt. Diese Liste der Funktionen findet ihr über die Startmenü Suche via „Windows-Funktionen aktivieren oder deaktivieren“, auch ein Menüpunkt in „Programme und Funktionen“.

Schaut die aktivierten Listenpunkte durch und deaktiviert auf Wunsch die Punkte. Ein Tooltip (bei Mouseover) verrät oftmals ausreichend, wofür die Funktion zuständig ist.
Ich habe Funktionen wie „Internetdruckclient“, „Windows DVD Maker“, „Windows Media Center“, „Plattform zu Windows-Minianwendungen“, „Remoteunterschiedskomprimierung“ und „Tablet-PC-Komponenten“ deaktiviert.

Update: Achtung! An dieser Stelle nicht „Windows Search“ deaktivieren, dann verschwindet die Suchleiste im Startmenü. Windows Search nur unter „Dienste“ deaktivieren.


Kleinkram:

Protokollierung deaktivieren: in der Registry unter HKEY_LOCAL_MACHINE\Software\Microsoft\WBEM\CIMOM die Einträge „EnableEvents“ und „Logging“ auf 0 setzen.

Werbeblocker: Werbung im Internet ist nicht nur anstrengend und nervig, sie verlangsamt auch den Aufbau einer Internetseite. Installiert Werbeblocker wie Adblock Plus in eurem Browser!

Registry Fehler suchen: CCleaner, RegCleaner und viele andere Programme suchen in der Registry nach fehlerhaften Einträgen und bereinigen diese. Das kann die Performance ebenfalls leicht verbessern.

Unnötige Programme deinstallieren: Programme und FUnktionen aufrufen und unnötige Programme deinstallieren, logisch.


Tuning Tools:
Das alles ist viel Arbeit und Fummelei, einige wenige kostenlose Tools übernehmen viele dieser Tuning Tipps. Für das Windows Tweaking ist aber 1 Freeware besonders gut geeignet und sehr zu empfehlen: Ultimate Windows Tweaker. Die kleine .exe Datei ist sehr mächtig, über 150 Tweaks können angewendet werden, sollte aber mit Vorsicht benutzt werden.


via, via, via, via, via

Wer sich als Einzelhändler mit dem Gedanken befasst, sein Geschäftsergebnis durch den Einstieg in den Onlinehandel zu verbessern, findet hier Informationen über ein Angebot von Host-Europe, das besonders auf diese Kundengruppe zugeschnitten ist. Der eigenständige E-Commerce-Anbieter startet aktuell eine Weihnachtsaktion, die das bereits günstige und professionelle Angebot eines eigenen Online-Shops noch attraktiver macht, bei überschaubaren Kosten.

Kostengünstiger Einstieg in den Onlinehandel

Besonders der lokale Einzelhändler scheut manchmal aus Kostengründen den Einstieg in den Online-Handel. Der Anbieter Host-Europe bietet deshalb seine professionellen Shoplösungen in der Weihnachtsaktion ohne Setup-Gebühren an. Die günstigen Angebote werden durch das Entfallen der Setup-Gebühr so noch ein wenig günstiger. Und bereits das Basic Paket enthält bei einer monatlichen Grundgebühr alle Funktionen, die für den Einstieg in den Online-Handel erforderlich sind. Für kleine Sortimente bis zu hundert Artikeln wird hier Einsteigern viel geboten. Für größere Sortimente zwischen 1000 und 20.000 bieten sich die Pakete Medium, Premium und Supreme an.

Alle professionellen Funktionen

Auch bei diesen Paketen beschränken sich die laufenden Kosten auf monatliche Grundgebühren von 19,99 bis zu 54,99 Euro. Die Einrichtung der Shops ist äußerst nutzerfreundlich. Die Software wird vorinstalliert und der Nutzer kann direkt mit der Einrichtung beginnen. Ein Assistent ermöglicht die Auswahl aus 250 verschiedenen professionellen Layouts, die selbstverständlich auch auf mobilen Endgeräten funktionieren. Die Produktverwaltung ist komfortabel und bietet alle gängigen Verkaufsoptionen. Auch die Anbindung an Facebook und Ebay ist problemlos möglich. Besonders erfreulich ist die Möglichkeit das Angebot mit ein paar Klicks auch in den Preisvergleichsportalen zu veröffentlichen.

Für den täglichen Einsatz

Auch Funktionen für die Warenwirtschaft und Buchhaltung stehen zur Verbindung. Und mit technischen Kenntnissen oder etwas Hilfe lassen sich auch diese Zahlen problemlos durch Datenexport in ein gutes Warenwirtschaftssystem einbuchen. Auch für alle anderen Aktivitäten rund um den Online-Handel sind die Pakete gut ausgestattet. Sowohl die Vorbereitung für den Versand als auch die Kundenverwaltung und die Suchmaschinenoptimierung entsprechen den Bedürfnissen des professionellen Online-Handels in diesem Umfang. Jedes Paket kann 30 Tage lang kostenlos getestet werden. Und natürlich können Kunden das Angebot bequem online buchen und erhalten im Rahmen der Weihnachtsaktion auch eine kostenlose Schulung.

Ich wurde gebeten einen detaillierten Blick auf die simplitec Power Suite zu werfen. Die Software soll PC Probleme schnell und einfach lösen und damit das System verbessern und beschleunigen.

Das Unternehmen simplitec GmbH hat es sich zum Ziel gesetzt leistungsfähige Systemsoftware für Jedermann zu entwickeln und dabei besondern einfach bedienbar zu gestalten.

Schon beim ersten Blick auf das Hauptfenster der Software wird klar, dass dieses Ziel besonders ernst genommen wird. Die Software wirkt sehr aufgeräumt und übersichtlich, die 3 Komponenten der Suite – simplifast, simpliclean und simplisafe – sind gut in die Oberfläche integriert. Design und Farben gefallen mir sehr.

Jede der 3 Komponenten testet das System in verschiedenen Punkten. Die Detailansicht verrät, was die Komponenten alles leisten: simplifast: Autostart optimieren, Windows Dienste optimieren, Internet-Tuning, Systemlaufwerke defragmentieren (Achtung bei SSDs), Highspeed Modus; simpliclean: Überflüssige Dateien löschen, Papierkorb sicher löschen, Energie sparen (bei simpliclean?), Registry bereinigen und defragmentieren; simplisafe: Internetspuren löschen, Treiber aktualisieren, Programme aktualisieren, Gelöschte Dateien retten, Gelöschte Dateien sicher vernichten. Das sind die wichtigsten Features für den PC Alltag.
Jeder dieser Punkte wird mit einem „Beeinträchtigungsrating“ in Form eines Balken versehen. Passende farbliche Gestaltung und eine Zahl verraten, wie kritisch der Zustand des Systems angeblich ist.

Die meisten Punkte und deren Funktion sind verständlich betitelt aber sicherheitshalber (und weil es schließlich auch zum Leitsatz der simplitec GmbH gehört) gibt es zu jedem Punkt eine ausführliche Hilfe. Alle Hilfen sind in einer Dokumentation gut strukturiert zusammengefasst.

Für noch mehr Hilfe stellt das Unternehmen ein Hilfevideo zur Software bereit.

Nach dem Scannen und Begutachten aller Punkte habe ich die starke Befürchtung, dass mein System etwas Plege bräuchte.

Etwas Kritik:

An dieser Stelle sind die Grenzen der kostenlosen Version der simplitec Power Suite leider schon erschöpft. Die Software scannt alle Punkte, beheben kann man die Probleme aber nur mit der Vollversion.
Somit ist die kostenlose Variante für den Nutzer nicht besonders hilfreich, außer zu erkennen, wo es im System klemmt. Mit dieser Erkenntnis wird man nun auf die Vollversion aufmerksam gemacht, die mit einem satten Preis von 49,99€ zu Buche schlägt. Dafür darf das Programm auf 3 PCs installiert werden.
Ich würde ja gerne sagen, dass das Programm mit fast 50€ zu den teuersten Programmen seiner Branche gehört, leider scheint das aber nur eine 1 Jahres Lizenz zu sein, es kostet also 50€ pro Jahr. Und das ist wirklich heftig!
Es wird schwierig sich mit diesem Preis vor die Konkurrenz zu stellen; nur ein Beispiel: das sehr bekannte TuneUp Utilities 2013 ist ebenfalls sehr benutzerfreundlich gestaltet, bietet eine Unmenge an Funktionen und kostet nur 40€, zeitlich unbegrenzt. Auch für diese 40€ erhält man eine Lizenz, die auf 3 PCs installiert werden darf.
Auch alle anderen Produkte der TopTenReviews aus der Kategorie „PC System Utilities“ sind günstiger.

Fazit:

simplitec GmbH hat mit der simplitec Power Suite eine sehr übersichtliche und nutzerfreundliche Software geschaffen, die alles kann, was Otto-Normal-Nutzer im Alltag braucht, um möglichst wenige Probleme mit dem PC zu kriegen. Optimieren, aufräumen, sichern, löschen und wiederherstellen wird einfacher denn je.
Einzig die Preispolitik sollte überdacht werden um das Produkt attraktiver zu machen. Bisher würde mich nur der Preis von einem Kauf abhalten.


Ein paar allgemeine Worte und meine eigene Meinung zu Optimierungssoftware:
Als ITler bin ich natürlich immer gespannt wo die typischen Aufräum/Optimier-Softwareprodukte versuchen das System zu beschleunigen; oft ist es ein schmaler Grad zwischen geringfügiger Beschleunigung und Instabilisierung oder Beeinträchtigung des Systems.

Beispiele:
Man kann den Indizierungsdienst von Windows deaktivieren und damit das System beschleunigen; man verzichtet damit aber auf die Suchfeatures von Windows. Viele Leute nutzen die Windows Suche selten oder gar nicht, manche jedoch schon. Sollte eine Optimierungssoftware nun also diesen Punkt optimieren? Gut für Einige, schlecht für Andere.
Man kann die Browserdaten, -history und -cache löschen und damit wieder etwas Ordnung schaffen. Aber: nach dieser Aktion ist das Surfen erstmal wieder langsamer; alle Daten (Cache, Cookies, History) müssen neu heruntergeladen und erstellt werden. Eben diese Daten werden erstellt um das Browser in Zukunft zu beschleunigen.
Sollte eine Omtimierungssoftware nun also diesen Punkt optimieren?

Also so einfach diese Tools auch sind; viele Optimierungen sind Geschmackssache, erfordern ein wenig Hintergrundwissen um sie sinnvoll zu kombinieren und je nach Situation einzustellen. Aber ich verstehe vollkommen, dass der PC Otto-Normal-User einfach nur mit so wenig Aufwand wie möglich das durchschnittlich Beste für seinen PC möchte. An dieser Stelle schaffen die Tools schnell Abhilfe, die in den meisten Fällen positive Effekte hat.

Gerade im Angebot, 2 ALBA BERLIN Tickets der PK2-4 für 6 Heimspiele in der o2 World! 2 Tickets für 15€(PK4), 20€(PK3), 25€(PK2).
Hier die Termine:
29.11.2012 gegen Asseco Prokom
06.12.2012 gegen Malaga
21.12.2012 gegen Oldenburg
06.01.2013 gegen Braunschweig
12.01.2013 gegen Trier
26.01.2013 gegen Gießen

3 Januar Termine, also sogar Weihnachtsgeschenk-fähig 😉
Für Basketball Fans finde ich den Deal recht cool.

Zum Deal!

Ich traf letztens auf einen sehr spezielles Java Problem, bei dem es dann zu Problemen bei der Serialisierung von Objekten kommt.
Ziel sollte es sein eine innere Klasse zu serialisieren während die äußere Klasse eine grafische Oberfläche und mehrere Ereignishandler beinhaltet und den JFileChooser verwendet. Dies schlägt fehl.

Hier der stark vereinfachte, aber trotzdem komplett lauffähige Aufbau eines solchen fehlerhaften Programms: (Video unten)

import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import javax.swing.JFrame;

public class GraphEditorGerüst extends JFrame implements MouseListener {
	
	ArrayList<Kreis> kreise = new ArrayList<Kreis>(); // globale Kreisvariable

	public GraphEditorGerüst(){
		super("GraphEditor");
		setSize(150, 100);
		addMouseListener(this);
	}
	
	public class Kreis implements Serializable {
		// innere, zu serialisierende, Klasse
		public static final long serialVersionUID = 3L;
		public int x, y, dx, dy, id, idcounter = 0;
		public Color c = Color.BLACK;	
		public Kreis(int x, int y, int dx, int dy, Color c) {
			this.x = x;
			this.y = y;
			this.dx = dx;
			this.dy = dy;
			this.c = c;
			this.id = ++idcounter;
		}
	}
	
	// Ereignishandler mouseClicked
	public void mouseClicked(MouseEvent me){
		// ein Dummykreis erstellen, der nachher geschrieben wird
		kreise.add(new Kreis(0,0,0,0,Color.BLACK));
		// neues JFileChooser Objekt
		JFileChooser fc = new JFileChooser();
		// JFileChooser Dialog anzeigen und Rückgabewert speichern
		int fcreturn = fc.showDialog(this, "Speichern");
		// wenn auf "Speichern" geklickt wurde
		if (fcreturn == JFileChooser.APPROVE_OPTION) {
			// ausgewählte Datei in ein File Objekt speichern
			File savefile = fc.getSelectedFile();
			try {
				FileOutputStream fos = new FileOutputStream(savefile);
				ObjectOutputStream oos = new ObjectOutputStream(fos);
				for (Kreis k : kreise) {
					// hier tritt der Fehler auf
					oos.writeObject(k);
				}
				oos.close();
				fos.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			catch (IOException e) {
				e.printStackTrace();
			}	
		}
	}	
	
	public static void main(String[] args){
		// Erzeugen eines Objektes von GraphEditorGerüst
		GraphEditorGerüst test = new GraphEditorGerüst();
		test.setVisible(true);
	}


	@Override
	public void mouseEntered(MouseEvent e) {}
	@Override
	public void mouseExited(MouseEvent e) {}
	@Override
	public void mousePressed(MouseEvent e) {}
	@Override
	public void mouseReleased(MouseEvent e) {}

}

Sieht an sich eigentlich unproblematisch aus.
Die innere Klasse soll serialisiert werden, hat das Interface implementiert und nutzt definitiv nur serialisierbare Datentypen und Elemente. Die äußere Klasse kümmert sich um die GUI und einige Ereignishandler. Einer dieser Handler enthält den JFileChooser zum Auswählen einer Datei, in die ein ObjectOutputStream nun die serialisierte innere Klasse schreiben soll. Es kommt beim Speichern, genauer gesagt bei der Ausführung von oos.writeObject, zu folgendem Fehler:

java.io.NotSerializableException: 
javax.swing.plaf.metal.MetalFileChooserUI

alertnativ auch auf

javax.swing.plaf.basic.BasicFileChooserUI$AcceptAllFileFilter

mit folgender Stack Trace:

Code anzeigenDen Code könnt ihr bequem mit den Links/Rechts Pfeiltasten horizontal bewegen.

java.io.NotSerializableException: javax.swing.plaf.metal.MetalFileChooserUI
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at javax.swing.event.EventListenerList.writeObject(Unknown Source)
	at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
	at javax.swing.JComponent.writeObject(Unknown Source)
	at sun.reflect.GeneratedMethodAccessor10.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteObject(Unknown Source)
	at java.awt.Window.writeObject(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at java.awt.Window.writeObject(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at java.util.ArrayList.writeObject(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at GraphEditor.actionPerformed(GraphEditor.java:191)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.AbstractButton.doClick(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue$4.run(Unknown Source)
	at java.awt.EventQueue$4.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

Video des Beispielcodes oben:

Hier die Problemanalyse:

Das Serialisieren von nicht-statischen inneren Klassen, deren äußere Klasse Ereignisempfänger ist, ist unter gewissen Umständen nicht möglich. Es wird versucht nicht nur die innere, sondern auch die äußere Klasse zu serialisieren, da die innere Klasse nicht-statisch ist. Wenn diese äußere Klasse ereignisverarbeitende Methoden verwendet, die nicht serialisierbare Objekte (z.B. JFileChooser in ActionPerformed()) enthält, so schlägt die Serialisierung der äußeren Klasse mit der Fehlermeldung „java.io.NotSerializableException“ auf dem nicht serialisierbaren Objekt „javax.swing.plaf.metal.MetalFileChooserUI“ (im Falle des JFileChooser) fehl.

Es ergeben sich 5 Lösungsmöglichkeiten:
1.) Die innere Klasse mit dem static Modifier versehen.
2.) Kein JFileChooser verwenden.
3.) Keine ereignisverarbeitenden Methoden in der Klasse verwenden, die das zu serialisierende Objekt – oder eine innere Klasse mit diesem Objekt – enthält.
4.) Auslagern der inneren, zu serialisierenden, Klasse.
5.) Auslagern aller Ereignisempfänger und Auslagern der inneren, zu serialisierenden, Klasse.

Die erste Lösung geht wohl am schnellsten und hilft in den meisten Fällen ohne weitere Probleme zu generieren. Die zwei nächsten Lösungen schränken die Möglichkeiten ein. Die vierte Lösung ist am einfachsten umzusetzen; nur die innere, zu serialisierende, Klasse wird in eine eigene Class Datei ausgelagert und entsprechend verwendet. Die fünfte Lösung lagert zusätzlich noch alle Ereignishandler aus (was sowieso nicht schlecht ist, da es zur logischen Trennung und Übersichtlichkeit beiträgt), kann aber, je nach Größe des Projekts, relativ aufwändig werden.

Hier der Code eines komplett lauffähigen Programms, bei der die zu serialisierende Klasse ausgelagert wurde:

GraphEditor.java:

Code anzeigenDen Code könnt ihr bequem mit den Links/Rechts Pfeiltasten horizontal bewegen.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GraphEditor extends JFrame implements MouseListener, MouseMotionListener, ActionListener {
	
	//Globale Variablen
	JTextField txt = new JTextField(10);
	JPanel panel1 = new JPanel();
	
	//Globale Variablen
	Kreis gezogenerKreis = null; //Kreis-Objekt zum Zwischenspeichern des bewegten Kreises
	
	//Kreisdurschnitt
	final int dX = 16, dY = 16;
	
	//Erstkonfiguration und Koordinatenkorrekturen
	int korrekturX = 0, korrekturY = 0;
	int korrekturX1 = 0, korrekturY1 = 0, korrekturX2 = 0, korrekturY2 = 0, configclickcounter = 1;
	boolean configured = false;
	
	//ArrayList zum Aufnehmen der Kreis-Objekte
	ArrayList<Kreis> kreise = new ArrayList<Kreis>(); 

	//Konstruktor der Klasse GraphEditor
	public GraphEditor(){
		
		//Aufruf des Konstruktors der Oberklasse
		super("GraphEditor");
		
		//Schließen des Fensters 
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		
		//Menüleiste
		JMenuBar mbar = new JMenuBar();
		this.setJMenuBar(mbar);
		
		//Menü
		JMenu mGraph = new JMenu("Graph");
		JMenu mVertex = new JMenu("Vertex");
		
		//Menüelemente
		JMenuItem mGraphOpen = new JMenuItem("open");
		JMenuItem mGraphNew = new JMenuItem("new");
		JMenuItem mGraphSave = new JMenuItem("save");
		JMenuItem mVertexInsert	= new JMenuItem("insert");
		JMenuItem mVertexMove = new JMenuItem("move");
		JMenuItem mVertexDelete = new JMenuItem("delete");
		JMenuItem mVertexNone = new JMenuItem("none");
		
		//Hinzufügen der Elemente zur Menüleiste
		mGraph.add(mGraphNew);
		mGraph.add(mGraphOpen);
		mGraph.add(mGraphSave);
		mVertex.add(mVertexInsert);
		mVertex.add(mVertexMove);
		mVertex.add(mVertexDelete);
		mVertex.add(mVertexNone);		
		mbar.add(mGraph);
		mbar.add(mVertex);
		
		//Haupt-Panel
		this.setLayout(new BorderLayout());
		panel1.setBackground(Color.white);
		this.add(panel1, BorderLayout.CENTER);
		panel1.addMouseListener(this);
		panel1.addMouseMotionListener(this);
		
		//unteres Panel für Label und Textfeld
		JPanel panel2 = new JPanel();
		this.add(panel2, BorderLayout.SOUTH);
		
		//Label
		JLabel label = new JLabel("Selected Action", JLabel.RIGHT);
		panel2.setLayout(new GridLayout(1,2,5,0));
		panel2.add(label);
		
		//Panel für Textfeld
		JPanel panel3 = new JPanel();
		panel3.setLayout(new FlowLayout(3));
		panel2.add(panel3);
		
		//Textfeld
		txt.setText("none");
		txt.setDisabledTextColor(Color.black);
		txt.setEnabled(false);
		panel3.add(txt);
		
		//ActionListener
		mVertex.addActionListener(this); // vertex:
		mVertexInsert.addActionListener(this);
		mVertexDelete.addActionListener(this);
		mVertexMove.addActionListener(this);
		mVertexNone.addActionListener(this);
		mGraph.addActionListener(this); // graph:
		mGraphNew.addActionListener(this);
		mGraphOpen.addActionListener(this);
		mGraphSave.addActionListener(this);
		
		//ActionCommands
		mVertex.setActionCommand("vertex"); // vertex:
		mVertexInsert.setActionCommand("insert");
		mVertexDelete.setActionCommand("delete");
		mVertexMove.setActionCommand("move");
		mVertexNone.setActionCommand("none");
		mGraph.setActionCommand("graph"); // graph:
		mGraphNew.setActionCommand("new");
		mGraphOpen.setActionCommand("open");
		mGraphSave.setActionCommand("save");
	}
	
	//Überschriebene Paint-Methode zum Zeichnen der Kreise
	public void paint(Graphics g) {
		super.paint(g);
		for (Kreis k: kreise) {
			g.setColor(k.c);
			g.fillOval(k.x - k.dx/2 + korrekturX, k.y - k.dy/2 + korrekturY, k.dx, k.dy);
		}
	}
	
	//ActionEvent
	public void actionPerformed(ActionEvent ae){
		//Zwischenspeichern
		String action = ae.getActionCommand();
		
		//werden unabhängig von der Erstkonfiguration immer ausgeführt
		if(action == "delete"){
			txt.setText("Vertex: delete");
		}
		if(action == "move"){
			txt.setText("Vertex: move");
		}
		if(action == "none"){
			txt.setText("none");
		}
		//wenn insert zum ersten Mal ausgewählt wird: Infofenster anzeigen
		if (configured == false && action == "insert") {
			int wahl = JOptionPane.showConfirmDialog(this, "" +
					"Bei der ersten Verwendung des Programms muss eine Konfiguration erfolgen. \n" +
					"Bitte klicken Sie an eine Stelle mittig im Zeichenbereich und danach\n " +
					"exakt in den weißen Punkt in der Mitte des gezeichneten Kreises!", 
					"Konfiguration nötig!", JOptionPane.OK_CANCEL_OPTION);
			if (wahl == JOptionPane.OK_OPTION) {
				txt.setText("Vertex: insert");
			}
		}
		//wenn Erstkonfiguration schon abgeschlossen ist
		else if (configured == true) {
			if(action == "insert"){
				txt.setText("Vertex: insert");	
			}
		}
		
		//Löschen der Kreise aus der Liste 
		if(action == "new") {
			kreise.clear();
			repaint();
		}
		
		//Speichern der gezeichneten Kreise
		if(action == "save") {
			JFileChooser fc = new JFileChooser();
			int fcreturn = fc.showDialog(this, "Speichern");
			if (fcreturn == JFileChooser.APPROVE_OPTION) {
	            File savefile = fc.getSelectedFile();
				try {
					FileOutputStream fos = new FileOutputStream(savefile);
					ObjectOutputStream oos = new ObjectOutputStream(fos);
					for (Kreis k : kreise) {
						oos.writeObject(k);
					}
					oos.close();
					fos.close();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
				catch (IOException e) {
					e.printStackTrace();
				}	
			}
		}
		
		//Öffnen einer bereits gespeicherten Datei mit Punkten
		if(action == "open") {
			kreise.clear();
			JFileChooser fc = new JFileChooser();
			int fcreturn = fc.showDialog(this, "Öffnen");
			if (fcreturn == JFileChooser.APPROVE_OPTION) {
	            File openfile = fc.getSelectedFile();
	            fc = null;
	            FileInputStream fis;
	            ObjectInputStream ois;
				try {
					fis = new FileInputStream(openfile);
					ois = new ObjectInputStream(fis);
					try {
						while (true) {
						kreise.add((Kreis) ois.readObject());
						repaint();
						}
					}
					catch (EOFException e) {
						System.out.println("Dateiende erreicht");
						ois.close();
						fis.close();
					}
				}
				catch (IOException e) {
					e.printStackTrace();
				} 
				catch (ClassNotFoundException e) {
					e.printStackTrace();
				}	
	        }
		}
		repaint();
	}
	
	//MouseEvents
	public void mouseClicked(MouseEvent me){
		repaint();
		int cursorX = me.getX();
		int cursorY = me.getY();
		//Erstkonfiguration der Koordinatenkorrektur starten, wenn noch nicht erfolgt
		if (configured == false) {
			//erster Klick der Erstkonfiguration, Textfeld mit "Vertex: insert" nur, wenn der Benutzer im Dialog "OK" geklickt hat
			if (configclickcounter == 1 && txt.getText().equals("Vertex: insert")) {
				//erstes Koordinatenpaar lesen
				korrekturX1 = me.getX();
				korrekturY1 = me.getY();
				configclickcounter++;
				/* Kreis mit den unkonfigurierten Standardkoordinaten zeichnen; 				
				 * dieser wird links oberhalb des Klickpunktes erscheinen, je nach Betriebssystem(/-version)
				 * und Windows-Design unterschiedlich!
				 * Ein kleiner weißer Kreis symbolisiert die Mitte, die angeklickt werden muss. */		 
				kreise.add(new Kreis(cursorX, cursorY, dX, dY));
				kreise.add(new Kreis(cursorX, cursorY, 2, 2, Color.WHITE));
			//zweiter Klick der Erstkonfiguration
			} else if (configclickcounter == 2 && txt.getText().equals("Vertex: insert")) {
				//Konfigurationskreise löschen
				kreise.clear();
				repaint();
				//zweites Koordinatenpaar lesen
				korrekturX2 = me.getX();
				korrekturY2 = me.getY();
				//Korrekturen errechnen
				korrekturX = korrekturX1 - korrekturX2;
				korrekturY = korrekturY1 - korrekturY2;
				//Konfiguration beenden, Infodialog anzeigen
				configured = true;
				JOptionPane.showConfirmDialog(this, "" +
						"Die Konfiguration ist abgeschlossen. \n" +
						"Koordinatenkorrektur für X: " + korrekturX + " | Y: " + korrekturY, 
						"Konfiguration abgschlossen!", JOptionPane.OK_CANCEL_OPTION);
			}
		}		
		//Erstkonfiguration beendet
		else if (configured == true){
			if(txt.getText().equals("Vertex: insert")){
				kreise.add(new Kreis(cursorX, cursorY, dX, dY));
			}
		}
		if(txt.getText().equals("Vertex: delete")){
			for(Kreis k : kreise){
				if(cursorX <= (k.x + dX/2.0) && cursorX >= (k.x - dX/2.0) && cursorY <= (k.y + dY/2.0) && cursorY >= (k.y - dY/2.0)){
					kreise.remove(k);
					break;
				} 
			}
		}
	}	
	
	public void mousePressed(MouseEvent me){
		if(txt.getText().equals("Vertex: move")){
			int cursorX = me.getX();
			int cursorY = me.getY();
			for(Kreis k : kreise){
				if(cursorX <= (k.x + dX/2.0) && cursorX >= (k.x - dX/2.0) && cursorY <= (k.y + dY/2.0) && cursorY >= (k.y - dY/2.0)){
					gezogenerKreis = k;					
				} 
			}
		}
	}
	public void mouseEntered(MouseEvent arg0){}
	public void mouseExited(MouseEvent arg0){}
	public void mouseReleased(MouseEvent arg0){
		gezogenerKreis = null;
	}

	//MouseMotionEvents
	public void mouseDragged(MouseEvent me) {
		if(txt.getText().equals("Vertex: move")){
			if(gezogenerKreis != null) {	
				gezogenerKreis.x = me.getX();
				gezogenerKreis.y = me.getY();	
				repaint();
			}
		}
	}
	public void mouseMoved(MouseEvent e){}
	
	//Main-Methode		
	public static void main(String[] args){
		
		//GraphEditor-Objekt
		GraphEditor ui = new GraphEditor();
		
		//Setzen der Größe und Sichtbarkeit des GraphEditor-Objekts
		ui.setSize(550, 350);
		ui.setVisible(true);
		
	}

}

Kreis.java:

Code anzeigenDen Code könnt ihr bequem mit den Links/Rechts Pfeiltasten horizontal bewegen.

import java.awt.Color;
import java.io.Serializable;

public class Kreis implements Serializable {
	//Innere Kreis-Klasse
	public static final long serialVersionUID = 3L;
	public int x, y, dx, dy, id;
	public Color c = Color.BLACK;	
	int counter = 0;
	// 2 verschieden überladene Konstruktoren ermöglichen die freie Farbwahl für jeden einzelnen Kreis
	public Kreis(int x, int y, int dx, int dy, Color c) {
		this.x = x;
		this.y = y;
		this.dx = dx;
		this.dy = dy;
		this.c = c;
		this.id = ++counter;
	}
	public Kreis(int x, int y, int dx, int dy) {
		this.x = x;
		this.y = y;
		this.dx = dx;
		this.dy = dy;
	}
	@Override
	public String toString() {
		return "x:"+ x + " y:" + y + " dx:" + dx + " dy:" + dy + " color:" + c.toString()+ "\n";

	}
}

Ich bin ein Freund von persönlichen Fotos auf gedruckten Leinwänden. Demnach horchte ich immer auf, wenn es Gutscheine für Leinwände gibt. Picanova, PosterXXL, meinfoto, alle vom selben Schlag, machen das mittlerweile sehr professionell und zuverlässig; mindestens 10 Leinwände habe ich dort schon gekauft.


Nun also von mir der Tipp: 29,90€ bezahlt, Leinwände im Wert von 100€ bestellt!

Zum Gutschein


Bei einem Format von 40x30cm könnt ihr da 4 Leinwände kaufen; das sind also nicht einmal 7,50€ pro Leinwand!
Die Leinwände werden bei Picanova mit lösemittelfreien Farben auf die Holzrahmen gespannt und werden somit fertig verschickt; nur noch das Aufhängen kostet Arbeit.

Viel Spaß damit.