【问题标题】:Disable AND grey out an SWT composite禁用 SWT 复合并将其变灰
【发布时间】:2016-11-16 21:21:00
【问题描述】:

我有一个Composite,我希望能够以编程方式启用/禁用它。 Control.setEnabled(boolean enabled) 方法可以正常工作,但它没有提供任何关于小部件被禁用的视觉信息。

我想做的是让禁用状态意味着小部件变灰。现在他们只是进入一个奇怪的状态,用户无法点击或对其执行任何操作。

【问题讨论】:

    标签: swt


    【解决方案1】:

    Composite 是一个容器控件,它使用布局保存其他控件 - 您实际上看不到组合,您只能看到它包含的控件。要禁用并在视觉上看到然后禁用,您必须在所有孩子上调用setEnabled(false),假设它们也不是容器。基本上,必须启用/禁用叶子小部件,您会看到视觉指示。

    禁用复合时您无法对小部件执行任何操作的原因是复合正在吞噬所有事件。尽管子小部件没有转发事件,但它们对父小部件的状态一无所知,因此它们不会变灰。

    【讨论】:

      【解决方案2】:

      问题确实是我禁用了复合而不是其中的控件。我最终做的是这样的:

      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);
         }
      }
      

      【讨论】:

      • 对 Fredrik 的帖子进行了额外的调整,这主要是我需要的。我有一种情况,除了禁用他们的孩子之外,还有一些选项卡文件夹和一些其他类型的复合材料需要被禁用。所以:` ... for (Control c : comp.getChildren()) recursiveSetEnabled(c, enabled); comp.setEnabled(启用); ... `
      • 这对于禁用控件树但排除某些控件也很有用,这在使用例如Composite...disable() 然后尝试重新启用某些控件。
      • 但是当您重新启用小部件时,您希望将以前禁用的小部件保持为禁用状态。使用此解决方案,您将启用一切。
      【解决方案3】:

      此处发布的其他解决方案非常原始。它们有几个缺点:

      • 即使一个控件在开始时被禁用,如果它的控件树被禁用然后启用,它将变为启用。您可能希望禁用此类控件。
      • 有时嵌套控件在其控件树被禁用时应保持启用状态。
      • 区分两种不同的禁用状态很有用:
        1. 禁用状态,没有可显示的信息。这应该清楚地以视觉方式向用户显示。
        2. 显示信息,但处于只读状态。能够在这种状态下复制文本字段中的文本很有用。

      下面的代码解决了这些问题。 它是 SWT 的最终启用/禁用器。

      它通过标记Widget.setData 来跟踪修改后的控件,因此它只启用之前禁用的控件。它在树状态下以不同的方式处理不同类型的控件:DISABLEDREAD_ONLYEDITABLE

      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);
              }
          }
      }
      

      这样做的一个限制是,即使在禁用状态下,仍然可以更改 TabFolder 控件中的活动选项卡。

      【讨论】:

        【解决方案4】:

        换句话说,你需要写这样的代码,给定一个Composite c

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

        【讨论】:

        • 并非如此 - 您需要递归整个控制堆栈。如果说您在复合材料中有一个窗扇并且您的小部件在窗扇中,这将不起作用。
        • 是的,我知道。我只是举个例子。
        猜你喜欢
        • 2014-05-12
        • 1970-01-01
        • 2011-01-21
        • 2013-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-27
        • 1970-01-01
        相关资源
        最近更新 更多