[SwingX] Utilitaire pour afficher un état "Occupé"
Bonjour,
Pour un petit programme, j'ai écrit une classe permettant facilement d'indiquer qu'un composant est indisponible le temps qu'une tâche de fonds s'éxecute.
Cette classe utilise en interne une JXBusyLabel de SwingX (requis pour fonctionner).
L'objectif premier est de pouvoir rendre "occupé" n'importe quel composant sans trop d'effort. Mon besoin était de pouvoir le faire sur une JTable (le temps qu'elle charge les données à afficher).
Créer un gestionnaire:
Code:
1 2 3 4 5
|
/** Create an handler for managing the "busy" state
* This handler can be used on the controller or model layer
*/
BusyHandler handler = BusyFactory.create( monComposant ); |
Indiquer que le composant est occupé:
Code:
1 2 3 4
|
/** Go on a busy state
*/
handler.busy(); |
Indiquer que le composant n'est plus occupé:
Code:
1 2 3 4
|
/** Return to a normal state
*/
handler.done(); |
ce qui donne sur une JTable (avec une animation)
http://z1.zod.fr/z/busy-nYq.png
Voici le code:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
| package org.divxdede.filemanager.ui.busy;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.Window;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import org.jdesktop.swingx.JXBusyLabel;
import org.jdesktop.swingx.JXPanel;
/**
* Utilitaire pour rendre "occupé" un composant swing.
* <p>
* Les méthodes <strong>create</strong> modifie le rendu d'un composant afin
* d'indiquer à l'utilisateur que ce dernier est occupé.
* <p>
* Un <code>BusyHandler</code> est retourné afin de permettre à l'appelant
* d'indiquer que la tâche occupant le composant est terminée.
*
* @author André Sébastien
*/
public abstract class BusyFactory {
/** Busy a specified component
* @param comp Component to create
* @return BusyHandler Handler for complete the task and stop the create state
*/
public static BusyHandler create( JComponent comp ) {
return create( comp , Color.GRAY );
}
/** Busy a specified component
* @param comp Component to create
* @param shadowColor Shadowing color used over the component while it is create
* @return BusyHandler Handler for complete the task and stop the create state
*/
public static BusyHandler create( JComponent comp , Color shadowColor ) {
return new BusyHandlerImpl(comp, shadowColor );
}
/** Create a component used as a glasspane
*/
private static JComponent createGlassPane() {
JXPanel panel = new JXPanel();
panel.setLayout(null);
panel.setOpaque(false);
panel.setName("busy-glasspane");
return panel;
}
/** Duplicate a layout component (location & size) on another component.
*/
private static void layout( JComponent source , JComponent dest ) {
Point point = source.getLocation();
Point rootPoint = SwingUtilities.convertPoint( source.getParent(), point , dest.getParent() );
dest.setLocation(rootPoint);
dest.setSize( source.getSize() );
}
/** BusyHandler implementation
*/
static class BusyHandlerImpl implements BusyHandler {
private JComponent comp = null;
private Color shadowColor = null;
private JComponent glassPane = null;
private Component[] comps = null;
public BusyHandlerImpl( JComponent comp , Color shadowColor ) {
this.comp = comp;
this.shadowColor = shadowColor;
}
public synchronized void busy() {
if( this.glassPane != null ) return;
synchronized( comp.getTreeLock() )
{
Window w = SwingUtilities.getWindowAncestor(comp);
if( w instanceof JFrame ) {
JFrame frame = (JFrame)w;
/** Get a glasspane component
*/
this.glassPane = (JComponent)frame.getGlassPane();
if( this.glassPane.getName() == null || !glassPane.getName().equals("busy-glasspane") ) {
this.glassPane = createGlassPane();
frame.setGlassPane( this.glassPane );
}
synchronized( this.glassPane.getTreeLock() )
{
/** Create a Busy Label
*/
JXBusyLabel label = new JXBusyLabel();
label.setHorizontalAlignment( label.CENTER );
/** Create a white-shadow
*/
JLabel shadow = null;
if( shadowColor != null ) {
shadow = new JLabel();
shadow.setBackground( new Color(shadowColor.getRed(),shadowColor.getGreen(),shadowColor.getBlue(),100) );
shadow.setOpaque(true);
}
/** Add the Busy label to the glasspane
*/
if( shadow != null ) this.glassPane.add( shadow );
this.glassPane.add( label );
if( shadow != null ) layout( comp , shadow );
layout( comp , label );
if( shadow != null ) {
this.comps = new Component[]{ shadow , label };
}
else
this.comps = new Component[]{ label };
/** Show the GlassPane if it's not the case
*/
this.glassPane.setVisible(true);
/** Start animation
*/
label.setBusy(true);
}
}
else {
throw new IllegalStateException("Component don't have a JFrame ancestor");
}
}
}
public synchronized void done() {
if( comps == null || glassPane == null ) return;
if( ! SwingUtilities.isEventDispatchThread() ) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
done();
}
} );
return;
}
synchronized( glassPane.getTreeLock() ) {
for(Component c : comps) {
if( c instanceof JXBusyLabel ) {
((JXBusyLabel)c).setBusy(false);
}
glassPane.remove(c);
}
}
glassPane = null;
comps = null;
}
}
} |
et
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package org.divxdede.filemanager.ui.busy;
/**
* BusyHandler allow to notify that the busy task is completed and that
* we can stop to render the component as a busy component.
*
* @author André Sébastien
*/
public interface BusyHandler {
/** Set the underlying task as busy.
*
*/
public void busy();
/** Done the underlying task.
*/
public void done();
} |
Cette classe n'est pas parfaite ( le rendu est peu configurable, etc...) mais ca peut être un point de départ pour implémenter une version plus "générale".
En esperant que ca peut re-servir.
Sébastien.