Geschichte von JavaFX: JavaFX 1, JavaFX 2, JavaFX 8

Ursprünglich wollte Sun/Oracle JavaFX als Flash-Ersatz im Internet positionieren, doch dafür ist die Kombination HTML5 + CSS3 + JavaScript zu attraktiv. JavaFX ist in erster Linie eine großartige GUI-Bibliothek für klassische Client-Anwendungen, die langsam auch auf mobile Endgeräte vorrückt. So nahm die Entwicklung auch unterschiedliche Richtungen an.

JavaFX ist schon sehr lange in Entwicklung und viele interne Swing-Entwickler wurden bei Sun/Oracle auf das Projekt angesetzt – umgekehrt passierte bei AWT/Swing nicht mehr viel, Bugfixes kommen aber immer noch brav. Im Jahr 2007 wurde JavaFX auf der SunOne-Konferenz vorgestellt, Ende 2008 erschien das Release JavaFX 1.0 zusammen mit der Programmiersprache JavaFX Script. Die besondere Sprache machte es einfach möglich, hierarchische Objektgrafen aufzubauen, und bot eine nette Syntax für Object-Binding, sodass Zustände synchronisiert werden konnten.

Im Oktober 2011 erschien JavaFX 2.0 mit vielen Neuerungen und auch Änderungen. So wurde JavaFX Script entfernt, denn Oracle wollte keine weitere Programmiersprache aufbauen, sondern eine pure Java API, die Entwickler dann von unterschiedlichen existierenden Skriptsprachen ansprechen können. Das ist sicherlich eine gute Entscheidung, denn unter JavaScript und Groovy[1] sieht das sehr schlank aus, fast wie mit JavaFX Script. Mit dem Update auf JavaFX 2.0 ändert sich auch die API, sodass alter Code angefasst werden musste. Heute ist JavaFX 1.x ist veraltet, genauso wie die Literatur.

JavaFX entwickelte sich immer mehr als Alternative zu Swing/AWT und so integrierte Oracle im August 2012 das Java FX 2.2 SDK und die Runtime in das JDK 7u6 and JRE 7u6. Der Schritt war ungewöhnlich, denn so große Ergänzungen waren bisher im JRE/JDK noch nie gemacht worden. Neben der Integration bewegte sich auch das ehemals geschlossene JavaFX in Richtung Open-Source und mündete in der Implementierung OpenJFX. Mit dem OpenJDK und OpenJFX lässt sich ein komplett freies Java-System mit GUI-Stack unter der GPL bauen, was strikte Linux-Distributionen freuen wird. Die Offenheit führte schon zu sehr spannenden Experimenten, etwa einer Java-Version für iOS.

Mit Java 8 zieht auch JavaFX 8 fest in die Distribution ein, der nächste Sprung mit 3D-Unterstützung.


[1] http://groovyfx.org/

Die SQL3-Datentypen ARRAY, STRUCT und REF

Seitdem JDBC 2.0 die SQL3-Datentypen unterstützt, sind weitere Spaltentypen über Java-Programme zugänglich:

  • ARRAY. Der Datentyp erlaubt eine Aufzählung mehrerer Werte wie ein Feld in einer Spalte.
  • STRUCT. Neue benutzerdefinierte Typen – auch UDTs (user-defined types) genannt –, die auf der Datenbankseite mit der SQL-Anweisung CREATE TYPE angelegt werden.
  • REF. Verweise auf strukturierte Typen.

Am Nützlichsten ist das Feld.

ARRAY

SQL-Felder werden in JDBC durch die Schnittstelle java.sql.Array behandelt. Nehmen wir in einer Tabelle eine Spalte Aktienverlauf an, die eine Liste (Array) von Zahlen enthält. Aus dem ResultSet gibt dann getArray() Zugriff auf die Informationen:

Array verlauf = rs.getArray( "Aktienverlauf" );

Die Variable verlauf verweist jetzt auf das Array-Objekt, was dem SQL ARRAY entspricht. Die Werte können nun entnommen werden, doch nicht mit einem Iterator, und auch nicht mit get(index) Funktionen, sondern wieder mit einem Aufruf getArray(). Es liefert ein Feld genau des passenden Typs zurück.

String[] verläufe = (String[]) verlauf.getArray();
for ( int i = 0; i < verläufe.length; i++ )
  ...

Neben dem lesenden getArray() setzt setArray() ein Feld, und updateArray() aktualisiert die Werte.

Inselraus: Die Farben des Systems über java.awt.SystemColor

Bei eigenen Java-Programmen ist es wichtig, dass diese sich so perfekt wie möglich in die Reihe der anderen Client-Programme einordnen, ohne großartig aufzufallen. Dafür muss ein Fenster die globalen Einstellungen wie den Zeichensatz und die Farben kennen. Für die Systemfarben gibt es die Klasse SystemColor, die alle Farben einer grafischen Oberfläche auf symbolische Konstanten abbildet. So ist SystemColor.text[1] die Hintergrundfarbe von Texteingabefeldern. Besonders praktisch ist dies bei Änderungen von Farben während der Laufzeit. Über diese Klasse können immer die aktuellen Werte eingeholt werden, denn ändert sich beispielsweise die Hintergrundfarbe der Laufleisten, ändert sich damit auch der RGB-Wert.

Die Systemfarben sind Konstanten von Typ SystemColor, was eine Unterklasse von Color ist. Damit lassen sich sich direkt nutzen, etwa über setColor(Color) oder über getRGB() der RGB-Anteil erfragen. Die Klasse SystemColor hat keine eigenen öffentlichen Methoden, sondern überschreibt nur toString().

Die Klasse deklariert die folgenden statischen finalen Variablen:

class java.awt.SystemColor extends Color implements Serializable

SystemColor

Welche Farbe darauf anspricht

desktop

Farbe des Desktop-Hintergrunds

activeCaption

Hintergrundfarben für Text im Fensterrahmen

activeCaptionText

Farbe für Text im Fensterrahmen

activeCaptionBorder

Rahmenfarbe für Text im Fensterrahmen

inactiveCaption

Hintergrundfarbe für inaktiven Text im Fensterrahmen

inactiveCaptionText

Farbe für inaktiven Text im Fensterrahmen

inactiveCaptionBorder

Rahmenfarbe für inaktiven Text im Fensterrahmen

window

Hintergrundfarbe der Fenster

windowBorder

Rahmenfarbe der Fenster

windowText

Textfarbe für Fenster

menu

Hintergrundfarbe für Menüs

menuText

Textfarbe für Menüs

text

Hintergrundfarbe für Textkomponenten

textText

Textfarbe für Textkomponenten

textHighlight

Hintergrundfarbe für hervorgehobenen Text

textHighlightText

Farbe des Texts, wenn dieser hervorgehoben ist

textInactiveText

Farbe für inaktiven Text

control

Hintergrundfarbe für Kontrollobjekte

controlText

Textfarbe für Kontrollobjekte

controlHighlight

normale Farbe, mit der Kontrollobjekte hervorgehoben werden

controlLtHighlight

hellere Farbe, mit der Kontrollobjekte hervorgehoben werden

controlShadow

normale Hintergrundfarbe für Kontrollobjekte

controlDkShadow

dunklerer Schatten für Kontrollobjekte

scrollbar

Hintergrundfarbe der Schieberegler

Info

Hintergrundfarbe der Hilfe

infoText

Textfarbe der Hilfe

Konstanten der Systemfarben

Hinweis: Die Klasse javax.swing.UIManager ist ein großer Assoziativspeicher, bei dem sich weitere Belegungen erfragen lassen. Es erfragt zum Beispiel UIManager.getColor("Table.background") die Tabellen-Hintergrundfarbe vom gerade eingestellen Look and Feel.[2]


[1] Sun verstößt mal wieder gegen die eigenen Namenskonventionen. Die finalen Variablen – Konstanten – sollten großgeschrieben werden. Das funktioniert bei den SystemColor-Objekten aber nicht, da es alle Bezeichnernamen schon in Großbuchstaben gibt, und zwar für Variablen vom Typ Byte, die Verweise in eine interne Tabelle darstellen.

[2] Die Seite http://www.devdaily.com/java/java-uimanager-color-keys-list liefert eine Auflistung der Schlüssel und ein Programm zur Anzeige.

Inselraus: Zeichensätze des Systems ermitteln

Um herauszufinden, welche Zeichensätze auf einem System installiert sind, liefert getAvailableFontFamilyNames() auf einem GraphicsEnvironment ein Feld mit Font-Objekten. Ein Objekt vom Typ GraphicsEnvironment beschreibt die Zeichensätze des Systems und liefert GraphicsDevice-Objekte. Ein GraphicsDevice ist eine Malfläche, also das, worauf das System zeichnen kann. Das kann der Bildschirm sein, aber auch ein Drucker oder eine Hintergrundgrafik. Die statische Fabrikmethode getLocalGraphicsEnvironment() liefert ein solches GraphicsEnvironment-Objekt.

Beispiel: Im folgenden Codesegment gibt eine Schleife alle Zeichensatznamen aus:

for ( String fonts : GraphicsEnvironment.
        getLocalGraphicsEnvironment().getAvailableFontFamilyNames() )
  System.out.println( fonts );

Auf meinem System liefert die Schleife die folgenden Ausgaben:

Arial

Arial Black

Arial Narrow

Wingdings

Wingdings 2

Wingdings 3

Zur API:

abstract class java.awt.GraphicsEnvironment

  • static GraphicsEnvironment getLocalGraphicsEnvironment()
    Liefert das aktuelle GraphicsEnvironment-Objekt.
  • abstract Font[] getAllFonts()
    Liefert ein Feld mit allen verfügbaren Font-Objekten in einer Größe von einem Punkt.
  • abstract String[] getAvailableFontFamilyNames()
    Liefert ein Feld mit allen verfügbaren Zeichensatzfamilien.
  • abstract String[] getAvailableFontFamilyNames(Locale l)
    Liefert ein Feld mit verfügbaren Zeichensatzfamilien, die zu einer Sprache l gehören.

Inselraus: n-Ecke zeichnen

In der Graphics-Klasse gibt es keine Methode, um regelmäßige n-Ecken zu zeichnen. Eine solche Methode ist aber leicht und schnell programmiert: Wir teilen dazu einfach einen Kreis in n Teile auf und berechnen die x- und y-Koordinaten der Punkte auf dem Kreis. Diese Punkte fügen wir einem Polygon-Objekt mittels der addPoint(…)-Methode hinzu. Eine eigene statische Methode drawVertex(…) übernimmt diese Polygon-Erstellung. Der letzte Parameter der Methode ist ein Wahrheitswert, der bestimmt, ob das n-Eck gefüllt werden soll oder nicht:

package com.tutego.insel.ui.graphics;

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

public class N_Vertex extends JPanel {

  private static final long serialVersionUID = -6314283966378303073L;

  @Override protected void paintComponent( Graphics g ) {
    VertexDrawer.drawVertex( g, getWidth() / 2, getHeight() / 2, 50, 6, true );
    VertexDrawer.drawVertex( g, getWidth() / 2, getHeight() / 2, 60, 6, false );
  }

  public static void main( String[] args ) {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    f.add( new N_Vertex() );
    f.setSize( 200, 200 );
    f.setVisible( true );
  }
}

class VertexDrawer {
  public static void drawVertex( Graphics g, int x, int y, int r, int n, boolean filled ) {
    Polygon p = new Polygon();

    for ( int i = 0; i < n; i++ )
      p.addPoint( (int) (x + r * Math.cos( i * 2 * Math.PI / n )),
                  (int) (y + r * Math.sin( i * 2 * Math.PI / n )) );

    if ( filled )
      g.fillPolygon( p );
    else
      g.drawPolygon( p );
  }
}

Update 1.6.0_21 (6u21)

Änderungen unter http://java.sun.com/javase/6/webnotes/6u21.html.

Interessantere Dinge:

Support for Customized Loading Progress Indicators

With Java SE 6u21, you can now enhance the loading experience of an application by providing a customized loading progress indicator (sometimes referred to as a progress bar) to better inform the end user of how much of the application has been downloaded during startup. See the following topics for more information:

 

Java VisualVM

Java VisualVM based on VisualVM 1.2.2 is included in Java SE 6u21. This release introduces the following features and enhancements:

  • HeapWalker performance improvements
  • VisualVM-Sampler performance improvements
  • BTrace4VisualVM plugin introduces BTrace 1.1
  • Profiling engine bugfixes
  • Built on NetBeans Platform 6.8

For more information, refer to the VisualVM releases page.

http://java.sun.com/javase/6/webnotes/BugFixes6u21.html

Einrücken von mit XMLStreamWriter geschriebenen XML-Dokumenten

Um mal eben schnell ein XML-Dokument zu schreiben ist XMLStreamWriter genau das richtige. Etwas traurig ist, dass er nicht, wie JAXB einen Schalter kennt, um das geschriebene XML-Dokument einzurücken. Hier bietet sich aber ein Filter an, der das tut. In den Klassenpfad nimmt man etwa die beiden Dateien

auf und dekoriert dann seinen eigenen Stream-Writer:

StringWriter stringWriter = new StringWriter(1024);
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = new IndentingXMLStreamWriter( factory.createXMLStreamWriter( stringWriter ) );
writer.writeStartDocument( „utf-8“, „1.0“ );

Java 6 Update 18

Die Änderungen http://java.sun.com/javase/6/webnotes/6u18.html sind vielfältig. Zum einen für die Systemkonfigurationen:

Dann:

Im JDK gibt es ein Update der Datenbank

Aus dem Bereich XML:

Und vieles mehr im Bereich Tuning und Fehlerbehebung.

Frage: Kann man alle Instanzen einer Klasse ermitteln?

Das geht nicht wirklich und wenn, dann nur mit großen Umwegen etwa über die Java Debugging API, mit der man sich an die JVM hängen kann. Auch ein Blick auf den Quellcode von jconsole und jmap/jhat helfen hier, weil die Tools genau das machen und Zahlen geben.

Der Objektgraf verändert sich ständig und so könnte man auch die Objekte stark referenzieren und den GC am Löschen hindern. Das würde zu einer großen Anzahl von Problemen führen. (Schwache Referenzen könnte das Problem abmildern, aber der GC muss hier Zusatzarbeit machen und die Laufzeit würde sich (messbar) verschlechtern.) Die Objekte sind ja immer eine Momentaufnahme. Da kämen ja Millionen von Objekten raus, wenn man etwa nach „Gib mir alle Strings“ fragt. Laufend ändert sich diese Menge.

Wenn der Nutzer diese Instanzen wirklich braucht, kann er sie an einer Objekt-Registry anmelden.

  • Von Hand kann man Exemplare etwa in eine Map<Class,List<?>> setzen. Das muss man nicht unbedingt manuell machen, sondern man kann hier einen Aspekt schreiben, der Bytecode in den Konstruktor für solch ein Anmelden einfügt. Dann ist das Abmelden aber noch so eine Sache. Das kann aber eine PhantomReference übernehmen und so meldet man das Objekt an der Registry wieder ab.
  • Wenn man Spring benutzt, deklariert ListableBeanFactory (implementiert etwa von XmlBeanFactory) eine Methode Map getBeansOfType(Class type) für genau diesen Fall.
  • Sind die Exemplare alle MBeans, ist es einfach, dann sind sie schon an einem Container registriert, und Query liefert sie sogar nach gewissen Kriterien.

Update JDK 1.6.0_14 (6u14)

Änderungen listet http://java.sun.com/javase/6/webnotes/6u14.html auf. Interessant sind meines Erachtens: Compressed Object Pointers und Garbage First (G1) Garbage Collector, weil diese Dinge sind, die für Java 7 vorgesehen waren. Aber nun kann man die schon mal “in the wild” testen, was eine gute Sache ist. Dann noch JAX WS 2.1.6 and JAXB 2.1.10 und ein Update von JavaDB (wobei Derby schon deutlich weiter ist, komisch).