2010-06-02 7 views
12

J'ai un Composite que je veux activer/désactiver par programme. La méthode Control.setEnabled(boolean enabled) fonctionne correctement, mais ne donne aucune information visuelle indiquant que le ou les widgets sont désactivés.Désactiver ET griser un composite SWT

Ce que je voudrais faire est d'avoir l'état désactivé signifie que les widgets sont grisés. À l'heure actuelle, ils entrent dans un état étrange où l'utilisateur est incapable de cliquer ou d'effectuer une action sur eux.

Répondre

10

Un Composite est un contrôle de conteneur qui contient d'autres contrôles à l'aide d'une mise en page. Vous ne pouvez pas vraiment voir un composite, vous ne pouvez voir que les contrôles qu'il contient. Pour désactiver et voir visuellement alors désactivé, vous devrez appeler setEnabled(false) sur tous les enfants, en supposant qu'ils ne sont pas aussi des conteneurs. Fondamentalement, pour activer/désactiver les widgets feuille et vous verrez une indication visuelle.

La raison pour laquelle vous ne pouvez rien faire avec les widgets lorsque vous désactivez le Composite est que le Composite mange tous les événements. Bien que les widgets enfants ne transmettent pas les événements, ils ne savent rien de l'état de leurs parents, ils ne sont donc pas grisés.

0

En d'autres termes, vous avez besoin d'écrire du code comme celui-ci, étant donné un Composite c:

for (Control child : c.getChildren()) 
    child.setEnabled(false); 
+2

pas vraiment - vous avez besoin de recouler toute la pile de contrôle.Cela ne fonctionnera pas si vous dites que vous avez une ceinture dans un composite et vos widgets sont dans la ceinture. – andyczerwonka

+0

Oui, je sais. Je donnais juste un exemple. – dplass

11

Le problème était en effet que je le composite et la désactivation pas les commandes à l'intérieur. Ce que j'ai fini par faire était quelque chose comme ceci:

public void recursiveSetEnabled(Control ctrl, boolean enabled) { 
    if (ctrl instanceof Composite) { 
     Composite comp = (Composite) ctrl; 
     for (Control c : comp.getChildren()) 
     recursiveSetEnabled(c, enabled); 
    } else { 
     ctrl.setEnabled(enabled); 
    } 
} 
+0

Un tweak supplémentaire à la poste de Fredrik, qui était surtout ce dont j'avais besoin. J'ai une situation où il y a des tabfolders et d'autres types de composites qui doivent être désactivés en plus d'avoir leurs enfants handicapés. donc: ' ... pour (contrôle c: comp.getChildren()) recursiveSetEnabled (c, a permis); comp.setEnabled (activé); ... ' –

+0

Ceci est également utile pour désactiver un arbre de commandes mais en excluant certaines commandes, ce qui n'est pas possible en utilisant par ex. Composite ... disable(), puis essayez de réactiver certains contrôles. – Gregor

+0

Cependant, lorsque vous réactivez les widgets, vous souhaitez les désactiver comme désactivés. Avec cette solution, vous allez tout activer. – Lii

0

Les autres solutions affichées ici sont plutôt primitives. Ils ont plusieurs défauts:

  • Même si un contrôle est désactivé pour commencer, il sera activé si son arbre de contrôle est désactivé, puis activé. Vous voulez probablement garder un tel contrôle désactivé.
  • Les contrôles imbriqués doivent parfois rester activés lorsque leur arborescence de contrôle est désactivée.
  • Il est utile de distinguer entre deux états différents: handicapés
    1. désactivé, pour montrer aucune information. Cela devrait être clairement indiqué visuellement à l'utilisateur.
    2. Affichage d'informations, mais en lecture seule. Il est utile de pouvoir copier du texte dans des champs de texte dans cet état.

Le code ci-dessous permet de résoudre ces problèmes. Il est le catalyseur/désactivateur ultime pour SWT.

Il garde la trace des contrôles modifiés en les marquant avec Widget.setData, de sorte qu'il active uniquement les contrôles qu'il a précédemment désactivés. Il gère différemment les différents types de contrôles dans les états d'arborescence: DISABLED, READ_ONLY et EDITABLE.

import java.util.Arrays; 
import java.util.HashSet; 
import java.util.Set; 

import org.eclipse.swt.widgets.Combo; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.swt.widgets.Control; 
import org.eclipse.swt.widgets.Label; 
import org.eclipse.swt.widgets.Text; 
import org.eclipse.ui.forms.widgets.ExpandableComposite; 

public class GuiEnabler { 
    /** 
    * Used to set the enable state of a tree of controls. 
    */ 
    public enum EnableState { 
     /** 
     * The control is disabled, for when there is no information to show in 
     * it. All controls, including labels, are disabled. 
     */ 
     DISABLED, 
     /** 
     * For when there is information to show in the control, but it should 
     * be read-only. Controls are disabled, except Text which is 
     * non-editable, and Lables, which are enabeled. 
     */ 
     READ_ONLY, 
     /** 
     * All controls are enabled and editable. 
     */ 
     EDITABLE 
    } 

    private static final String ENABLED_KEY = GuiEnabler.class.getName() + ".disabled"; 
    private static final String EDITABLE_KEY = GuiEnabler.class.getName() + ".read_only"; 

    /** 
    * Disables or makes read-only {@code control} and all its child controls (recursively). 
    * Also restores the state of controls previously disabled by this method. The action 
    * performed on the controls is determined by {@link EnableState enableState}. 
    * 
    * @param excluded These controls (and their children) are not modified by 
    * the method. 
    */ 
    public static void recursiveUpdateEnableState(Control control, EnableState enableState, Control... excluded) { 
     updateEnabledState(control, enableState, new HashSet<>(Arrays.asList(excluded))); 
    } 

    /** 
    * See {@link GuiEnabler#recursiveUpdateEnableState(Control, EnableState, Control...)}. 
    */ 
    public static void updateEnabledState(Control control, EnableState enableState, Set<Control> excluded) { 
     if (excluded.contains(control)) { 
      return; 
     } else if (control instanceof ExpandableComposite) { 
      updateEnabledState(((ExpandableComposite) control).getClient(), enableState, excluded); 
     } else if (control instanceof Composite && !(control instanceof Combo)) { 
      for (Control child : ((Composite) control).getChildren()) { 
       updateEnabledState(child, enableState, excluded); 
      } 
     } else { 
      updateControl(control, enableState); 
     } 
    } 

    /** 
    * Updates a single control to have its proper state for enableState. 
    */ 
    private static void updateControl(Control control, EnableState enableState) { 
     if (enableState == EnableState.DISABLED) { 
      makeDisabled(control); 
     } else if (enableState == EnableState.READ_ONLY) { 
      if (control instanceof Text) { 
       makeNonEditable((Text) control); 
       makeEnabled(control); 
      } if (control instanceof Label) { 
       makeEnabled(control); 
      } else { 
       makeDisabled(control); 
      } 
     } else if (enableState == EnableState.EDITABLE) { 
      makeEnabled(control); 
      if (control instanceof Text) makeEditable((Text) control); 
     } 
    } 


    private static void makeEnabled(Control control) { 
     if (control.getData(ENABLED_KEY) != null) { 
      control.setData(ENABLED_KEY, null); 
      control.setEnabled(true); 
     } 
    } 

    private static void makeDisabled(Control control) { 
     if (control.getEnabled()) { 
      control.setData(ENABLED_KEY, "marked"); 
      control.setEnabled(false); 
     } 
    } 

    private static void makeEditable(Text text) { 
     if (text.getData(EDITABLE_KEY) != null) { 
      text.setData(EDITABLE_KEY, null); 
      text.setEditable(true); 
     } 
    } 

    private static void makeNonEditable(Text text) { 
     if (text.getEditable()) { 
      text.setData(EDITABLE_KEY, "marked"); 
      text.setEditable(false); 
     } 
    } 
} 

Une limitation est que même dans l'état désactivé, il est encore possible de changer l'onglet actif dans un contrôle TabFolder.

Questions connexes