CSS engine Swing

TK-UI fournit des implémentations de moteurs CSS qui sont capables d'appliquer des styles CSS à des Component Swing . Veuillez vous reporter à la section Téléchargement pour télécharger le distribuable du moteur CSS Swing et ses examples.

Cette section explique comment utiliser les moteurs CSS Swing à travers d'exemples simples. Vous pourrez trouvez des exemples plus complexes dans le répertoire test du distribuable org.akrogen.tkui.css.swing* . Il existe deux manières d'appliquer des styles CSS à des Components Swing :

La section Selectors permet de décrire tous les types de selectors que l'on peut écrire avec des Components Swing.

Les moteurs CSS Swing sont configurables, veuillez vous reporter à la section CSSEngine API pour plus d'informations.

Swing CSS engine

Swing selector

Voici un exemple basique de code Swing qui permet d'appliquer la feuille de style CSS avec les sectors de type Swing (autrement dit les noms des classes des Components Swing sont ici utilisés en tant que selector) :
JLabel { 
  color:red;
} 

JTextField {
  background-color:green;
}
à une interface Swing constituée d'un JLabel et JTextField. Dans cet exemple la classe org.akrogen.tkui.css.swing.engine.CSSSwingEngineImpl est utilisée.
// Create Swing CSS Engine
CSSEngine engine = new CSSSwingEngineImpl();
// Parse style sheet
engine.parseStyleSheet(new StringReader(
	"JLabel {color:red;} JTextField {background-color:green;}"));

/*---   Start UI Swing ---*/
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel();
frame.getContentPane().add(panel);

// Label
JLabel label1 = new JLabel();
label1.setText("Label 0");
panel.add(label1);

// Text
JTextField text1 = new JTextField();
text1.setText("bla bla bla...");
panel.add(text1);

/*---   End UI Swing  ---*/

// Apply Styles
engine.applyStyles(frame, true);

frame.pack();
frame.setVisible(true);
Apres éxécution de ce code, la fenêtre Swing s'affiche :

HTML selector

Voici un exemple basique de code Swing qui permet d'appliquer la feuille de style CSS avec les selectors de type HTML (autrement dit les noms HTML sont ici utilisés en tant que selector) :
label { 
  color:red;
} 

input {
  background-color:green;
}
à une interface Swing constituée d'un JLabel et JTextField. Dans cet exemple la classe org.akrogen.tkui.css.swing.engine.html.CSSSwingHTMLEngineImpljava est utilisée.
// Create Swing CSS Engine
CSSEngine engine = new CSSSwingHTMLEngineImpl();
// Parse style sheet
engine.parseStyleSheet(new StringReader(
	"JLabel {color:red;} JTextField {background-color:green;}"));

/*---   Start UI Swing ---*/
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel();
frame.getContentPane().add(panel);

// Label
JLabel label1 = new JLabel();
label1.setText("Label 0");
panel.add(label1);

// Text
JTextField text1 = new JTextField();
text1.setText("bla bla bla...");
panel.add(text1);

/*---   End UI Swing  ---*/

// Apply Styles
engine.applyStyles(frame, true);

frame.pack();
frame.setVisible(true);
Apres éxécution de ce code, la fenêtre Swing s'affiche :

Pour gérer les noms HTML en tant que selector, un mapping entre le Component Swing et le nom HTML est effectué dans la méthode getLocalName de l'instance CSSStylableElement qui wrappe le Component Swing. Voici un tableau du mapping nom HTML/Component Swing :

Nom HTML Component Swing
body javax.swing.JFrame
textarea javax.swing.JTextArea
input[type=password] TODO
input[type=text] javax.swing.text.JTextComponent
input[type=radio] javax.swing.JRadioButton
input[type=checkbox] javax.swing.JCheckBox
input[type=button] javax.swing.JButton
select javax.swing.JComboBox
label javax.swing.JLabel
canva TODO
a TODO
div javax.swing.JRootPane, javax.swing.JPanel, javax.swing.JLayeredPane
tree javax.swing.JTree
listbox javax.swing.JTable

Inline style

Dans les pages WEB HTML, il est possible de définir des styles inlines sur des elements HTML à l'aide de l'attribut style :
<input type="text" 
    id="MyId" 
    style="color:red;background-color:yellow;" />
Il est aussi possible de gérer le style en Javascript comme ceci :
var input = document.getElementById('MyId');
input.style.color='red';
input.style.backgroundColor='yellow';
L'implémentation du moteur CSS Swing est capable de gérer ce même type de problématique.

Inline style (1)

Par défaut en Swing, l'attribut style est géré à l'aide de la méthode putClientProperty d'un JComponent Swing en mettant le style CSS inline avec la clé style , comme ceci :
JTextField text = new JTextField();
text.setText("bla bla bla");
text.putClientProperty("style", "color:red;background-color:yellow;");
...
engine.applyStyles(frame, true);

Inline style (2)

Il est possible de récupérer une instance org.w3c.dom.css.CSS2Properties qui definit tous les getters/setters des propriétés CSS2 et ensuite de definir les styles à utiliser (comme en Javascript) :
JTextField text = new JTextField();
text.setText("bla bla bla");
CSSStylableElement stylableElement = (CSSStylableElement) engine.getElement(text);
CSS2Properties style = stylableElement.getStyle();
style.setColor("red");
style.setBackgroundColor("yellow");

Inline style (3)

Enfin il est possible d'utiliser la méthode parseAndApplyStyleDeclaration de engine comme ceci :
JTextField text = new JTextField();
text.setText("bla bla bla");
engine.parseAndApplyStyleDeclaration(text, "color:red;");

Selectors

Cette section reprend les spécification w3c selector et l'adapte au moteur CSS Swing.

Pattern matching

Pattern Description Décrit dans la section
* s'applique à n'importe quel Component Swing.
E s'applique à n'importe quel Component Swing E. E est défini par le nom de la classe Swing (CSSSwingEngineImpl) ou le nom HTML du Component (CSSSwingHTMLEngineImpl).
E F s'applique à n'importe quel Component Swing F qui est descendant d'une widget E (ex : JLabel contenu dans un JPanel). Descendant selectors
E:focus, E:hover s'applique à n'importe quel Component Swing durant certaines actions utilisateur. The dynamic pseudo-classes
E[foo="warning"] s'applique à n'importe quel Component Swing E dont l'attribut "foo" à exactement la valeur "warning"). Attribute selectors
E.className s'applique à n'importe quel Component Swing E qui ont class de nom className. Class selectors
E#myid s'applique à n'importe quel Component Swing qui ont un id égale à "myid". ID selectors

Descendant selectors

JPanel JLabel { 
  color:red;
} 
JLabel { 
  color:green;
}

Attribute selectors

Matching attributes and attribute values

Il est possible d'utiliser des attributs dans les styles CSS avec Swing. Il existe plusieurs type d'attribut :

  • attribut de type getter : ce type d'attribut permet de retrouver par introspection la valeur d'un getter d'un Component Swing. Par exemple le Component Swing JTextField possède une méthode isEditable qui retourne true si le Component est éditable. Il est possible d'écrire un style comme ceci :
    JTextField[editable=true] { 
      color:red;
    }
  • attribut de type custom : ce type d'attribut permet de gérer ses valeurs d'attributs à l'aide de la méthode putClientProperty d'un JComponent Swing. Si on définit putClientProperty comme ceci :
    JTextField text = ... 
    text.putClientProperty("foo", "warning");
    On peut écrire un style comme ceci :
    JTextField[foo="warning"] { 
      color:red;
    }

Class selectors

Par défaut l'information class est gérée avec la méthode putClientProperty du JComponent Swing :

.redColor { 
  color:red;
} 

.greenColor {
  color:green;
}
JLabel label = new JLabel();
label.putClientProperty("class", "redClass");

ID selectors

Par défaut l'information id est gérée avec la méthode putClientProperty du JComponent Swing :
JLabel#MyId { 
  color:red;
} 

JLabel {
  color:green;
}
JLabel label = new JLabel();
label.putClientProperty("id", "MyId");

Pseudo-classes

The dynamic pseudo-classes : :hover, :active, and :focus

JTextField:focus { 
  color:red;
} 

JTextField:hover {
  color:green;
}

JToolTip

Il est possible de gérer les tooltip des Components Swing pour par exemple appliquer le style CSS suivant :

JToolTip {
	background-color:yellow; 
	font:14 bold;
}

JLabel JToolTip {
	background-color:orange; 
	font:20 Serif italic normal;
	border-color:red;
}
Cet exemple permet de distinguer les JToolTip de n'importe quel Component Swing avec ceux des Component Swing JLabel.

Les component JToolTip sont un cas particulier, car il sont détruit lorsque le tooltip disparaît et recréés lorsque le tooltit apparaît. Il faut donc appliquer le style CSS lorsque le JToolTip est ajouté à l'interface. Swing permet de détecter l'ajout d'un Component à l'aide de la méthode addAWTEventListener de ToolKit. Pour gérer les ToolTip, il faut ajouter le code suivant qui permet d'appliquer le style sur un JToolTip :

// Apply styles CSS to JToolTip
Toolkit.getDefaultToolkit().addAWTEventListener(
new AWTEventListener() {
	public void eventDispatched(AWTEvent e) {
		ContainerEvent cevt = (ContainerEvent) e;
		Component component = cevt.getChild();
		if (component instanceof JToolTip) {
			JToolTip toolTip = (JToolTip) component;
			engine.applyStyles(toolTip, false);
		}
	}
}, AWTEvent.CONTAINER_EVENT_MASK);
Voici l'exemple complet :

// Create Swing CSS Engine
final CSSEngine engine = new CSSSwingEngineImpl();
// Parse style sheet
engine.parseStyleSheet(new StringReader(
	"JLabel {color:red;} " +
	"JTextField {background-color:green;}" +
	"JToolTip {background-color:yellow; font:14 bold;}" +
	"JLabel JToolTip {background-color:orange; font:20 Serif italic normal;border-color:red;}"));

/*---   Start UI Swing ---*/
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel();
frame.getContentPane().add(panel);

// Label
JLabel label1 = new JLabel();
label1.setText("Label 0");
label1.setToolTipText("JLabel tool tip.");
panel.add(label1);

// Text
JTextField text1 = new JTextField();
text1.setText("bla bla bla...");
text1.setToolTipText("JTextField tool tip.");
panel.add(text1);

/*---   End UI Swing  ---*/

// Apply Styles
engine.applyStyles(frame, true);

// Apply styles CSS to JToolTip
Toolkit.getDefaultToolkit().addAWTEventListener(
		new AWTEventListener() {
			public void eventDispatched(AWTEvent e) {
				ContainerEvent cevt = (ContainerEvent) e;
				Component component = cevt.getChild();
				if (component instanceof JToolTip) {
					JToolTip toolTip = (JToolTip) component;
					engine.applyStyles(toolTip, false);
				}
			}
		}, AWTEvent.CONTAINER_EVENT_MASK);
frame.pack();
frame.setVisible(true);