août
2009
A l’étape du billet précédant [step13] nous avons mis en place le layout automatique. Dans ce billet nous allons améliorer l’aspect visuel des figures draw2d des states et des actions :
- les states seront représentés par l’icône gear.gif .
- les actions seront représentées par un rectangle de couleur jaune pâle (couleur personnalisée) avec une bordure noire.
Vous pouvez télécharger le projet org.example.workflow_step14.zip présenté dans ce billet.
SWT Color#dispose() / Font#dispose()
A ce stade nous n’avons pas encore utilisé d’images ni personnalisé de couleurs (nous utilisons les couleurs systèmes provenant de la constante GEF org.eclipse.draw2d.ColorConstants). Draw2d utilise les classes ressources SWT org.eclipse.swt.graphics.Image et org.eclipse.swt.graphics.Color pour personnaliser les figures drawd2. Ces 2 ressources SWT possédent une méthode dispose() qui doit être apppelée lorsque la ressource n’est plus utilisée par le programme. En effet SWT sollicite le système d’exploitation lorsqu’il créé une ressource SWT Color ou Image. Une fois que la ressource SWT n’est plus utilisée, l’appel de la méthode dispose() permet d’avertir le système d’exploitation que la ressource n’est plus utilisée (pour qu’il puisse libérer sa mémoire).
Une ressource SWT Color, Image est associée à une Thread SWT org.eclipse.swt.widgets.Display qui gère la connection entre SWT et le système d’exploitation.
StateTypeFigure
Dans cette section nous allons représenter un state par l’icône gear.gif :
Copiez l’image gear.gif dans le répertoire icons/graphical du projet org.example.workflow.editor :
e
Il est important d’avoir à l’esprit que qand une Image est créée, elle doit être libérée lorsque qu’elle n’est plus utilisée, ce qui signifie la méthode Image#dispose() doit être appelée :
- à la fermeture de l’editeur de workflow.
- OU à la fermeture de l’IDE Eclipse (lorsque le Display SWT se libère).
Personnellement je préfère la deuxième solution car ceci permet de faire partager la même image pour tous les editeur de workflow ouverts. De plus la création de l’image s’effectuera qu’une seule fois et pas à chaque ouverture
d’un éditeur de workflow.
Notre projet contient un wizard de création d’un fichier workflow.xml. Ce wizard utilise l’image icons/full/wizban/NewWorkflow.gif :
Il est générée par EMF. Voici le code de l’initialisation du wizard qui indique l’image à utiliser :
this.workbench = workbench;
this.selection = selection;
setWindowTitle(WorkflowEditorPlugin.INSTANCE.getString("_UI_Wizard_label"));
setDefaultPageImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(WorkflowEditorPlugin.INSTANCE.getImage("full/wizban/NewWorkflow")));
}
Le code qui nous intérèsse est :
setDefaultPageImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(WorkflowEditorPlugin.INSTANCE.getImage("full/wizban/NewWorkflow")));
La classe EMF générique org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry permet de gérer un repository d’images :
- qui évite de créer la même image plusieurs fois
- qui libère l’image lorsque le Display SWT associé à l’image est libéré :
protected void handleDisplayDispose()
{
for (Image image : table.values())
{
image.dispose();
}
table = null;
}
protected void hookDisplayDispose(Display display)
{
display.disposeExec
(new Runnable()
{
public void run()
{
handleDisplayDispose();
}
});
}
Nous allons utiliser cette classe pour récupérer l’image icons/graphical/gear.gif. Modifiez la classe StateTypeFigure comme suit :
import org.eclipse.draw2d.Label;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.example.workflow.presentation.WorkflowEditorPlugin;
public class StateTypeFigure extends Label {
public StateTypeFigure() {
super.setIcon(ExtendedImageRegistry.INSTANCE
.getImage(WorkflowEditorPlugin.INSTANCE
.getImage("graphical/gear.gif")));
}
public void setName(String name) {
super.setText(name);
}
}
Nous n’avons plus besoin de la méthode StateTypeFigure#paintFigure(Graphics graphics) qui s’occupait de dessiner une ellipse. Relancez le plugin et vous pourrez voir les states représentés par l’icône gear.gif :
Le libélle des state est un peu trop près de l’icône gear. Il est possible de décaler ce libéllé vers la droite à l’aide du code suivant :
super.setIconTextGap(5);
Voici le code en entier de StateTypeFigure :
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.example.workflow.presentation.WorkflowEditorPlugin;
public class StateTypeFigure extends Label {
public StateTypeFigure() {
super.setIcon(ExtendedImageRegistry.INSTANCE
.getImage(WorkflowEditorPlugin.INSTANCE
.getImage("graphical/gear.gif")));
super.setIconTextGap(5);
}
public void setName(String name) {
super.setText(name);
}
}
ActionTypeFigure
Nous souhaions représenter nos actions par des rectangles jaunes pâles avec une bordure noire.
Figure#setOpaque
Actuellement voici le code de ActionTypeFigure :
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.Label;
public class ActionTypeFigure extends Label {
public ActionTypeFigure() {
super.setForegroundColor(ColorConstants.black);
}
@Override
protected void paintFigure(Graphics graphics) {
graphics.setBackgroundColor(ColorConstants.orange);
graphics.fillRectangle(getBounds());
super.paintFigure(graphics);
}
public void setName(String name) {
super.setText(name);
}
}
Ici nous avons re-défini la méthode paintFigure(Graphics graphics) pour dessiner un rectangle avec un fond orange. Mais nous pouvons avoir le même code sans être obligé de redefinir cette méthode comme ceci :
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Label;
public class ActionTypeFigure extends Label {
public ActionTypeFigure() {
super.setForegroundColor(ColorConstants.black);
super.setBackgroundColor(ColorConstants.orange);
super.setOpaque(true);
}
public void setName(String name) {
super.setText(name);
}
}
La couleur de fond est mise dans le constructuer avec
super.setBackgroundColor(ColorConstants.orange);
mais pour que cette couleur soit pris en compte, il faut ajouter le code
super.setOpaque(true);
sinon la figure action apparaît blanche.
WorkflowColorConstants
Jusqu’a maintenant nous avons utilisé des couleurs systèmes provenant de l’interface GEF org.eclipse.draw2d.ColorConstants. Ici nous souhaitons représenter les actions avec une couleur de fond jaune pâle, couleur que nous allons créer. Une couleur utilisé dans draw2d est représentée par une instance Color SWT. Pour créer cette couleur nous allons créer une interface WorkflowColorConstants avec nos couleurs personnalisées comme ceci :
import org.eclipse.swt.graphics.Color;
public class WorkflowColorConstants {
public static final Color lightYellow = new Color(null, 255, 255, 206);
}
C’est d’ailleurs ce que fait le projet d’exemple GEF org.eclipse.gef.examples.logic en définissant l’interface org.eclipse.gef.examples.logicdesigner.figures.LogicColorConstants :
import org.eclipse.swt.graphics.Color;
public interface LogicColorConstants
{
public final static Color andGate = new Color(null, 220,70,80);
public final static Color orGate = new Color (null, 0, 134, 255);
public final static Color xorGate = new Color (null, 240,240,40);
public final static Color logicGreen = new Color(null, 123,174,148);
public final static Color logicHighlight = new Color(null,66,166,115);
public final static Color connectorGreen = new Color(null,0,69,40);
public final static Color logicBackgroundBlue = new Color(null, 200, 200, 240);
public final static Color ghostFillColor = new Color(null, 31, 31, 31);
}
Ceci marche bien, mais comme nous avons vu, une instance Color SWT doit être libérée (méthode Color#dispose())
quand elle n’est plus utilisée. Il n’y aurra certes pas beaucoup d’instance Color qui ne seront pas libérés, mais étant pointilleux, cette solution ne me satisfait pas totalement.
ColorRegistry
Pour régler ce problème nous allons créer un registry de Color SWT, qui libèrera les Color SWT lorsque le Display SWT se libèrera.
Créez la classe org.example.workflow.presentation.graphical.color.ColorRegistry comme suit :
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
public class ColorRegistry {
public final static ColorRegistry INSTANCE = new ColorRegistry();
private Display display;
private Map<RGB, Color> colors = new HashMap<RGB, Color>();
public ColorRegistry() {
this(Display.getCurrent());
}
public ColorRegistry(Display display) {
this.display = display;
hookDisplayDispose(display);
}
public Color getColor(int red, int green, int blue) {
return getColor(new RGB(red, green, blue));
}
public Color getColor(RGB rgb) {
Color color = colors.get(rgb);
if (color != null)
return color;
color = new Color(display, rgb);
colors.put(rgb, color);
return color;
}
protected void handleDisplayDispose() {
for (Color color : colors.values()) {
color.dispose();
}
colors = null;
}
protected void hookDisplayDispose(Display display) {
display.disposeExec(new Runnable() {
public void run() {
handleDisplayDispose();
}
});
}
}
WorkflowColorConstants
Modifiez la classe WorkflowColorConstants pour utiliser notre ColorRegisrty comme suit :
import org.eclipse.swt.graphics.Color;
public class WorkflowColorConstants {
public static final Color lightYellow = ColorRegistry.INSTANCE.getColor(255, 255, 206);
}
ActionTypeFigure
Nous pouvons maintanenat utiliser notre couleur jaune pâle. Modifiez la classe ActionTypeFigure comme suit :
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.LineBorder;
import org.example.workflow.presentation.graphical.color.WorkflowColorConstants;
public class ActionTypeFigure extends Label {
public ActionTypeFigure() {
super.setForegroundColor(ColorConstants.black);
super.setBackgroundColor(WorkflowColorConstants.lightYellow);
super.setOpaque(true);
super.setBorder(new LineBorder(1));
}
public void setName(String name) {
super.setText(name);
}
}
Relancez le plugin et vous pourrez constater que les actions sont représentées par des rectangles jaunes pâles avec une bordure noire :
Conclusion
La représentation graphique de notre workflow est maintenant terminée. Dans les prochains billets nous allons mettre en place la Palette d’outils GEF qui permettra à partir d’outil de la palette, d’ajouter des figures states, actions et connections dans la page Graphics GEF.
Articles récents
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step5]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step4]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step3]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step2]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step1]
Commentaires récents
- Conception d’un Editeur Eclipse de workflow XML [step 0] dans
- Conception d’un Editeur Eclipse de workflow XML [step 19] dans
- Conception d’un Editeur Eclipse de workflow XML [step 7] dans
- Conception d’un Editeur Eclipse de workflow XML [step 7] dans
- Conception d’un Editeur Eclipse de workflow XML [step 7] dans