禁用AND灰显SWT复合

时间:2010-06-02 12:31:28

标签: swt

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

我想要做的是让残疾人状态意味着小工具是灰色的。现在他们只是进入一个奇怪的状态,用户无法点击或执行任何操作。

4 个答案:

答案 0 :(得分:12)

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

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

答案 1 :(得分:11)

Composite是一个容器控件,它使用布局来保存其他控件 - 您无法真正看到复合,只能看到它所拥有的控件。要禁用并直观地看到已禁用,您必须在所有孩子身上调用setEnabled(false),假设他们也不是容器。基本上,要启用/禁用叶子小部件,您将看到视觉指示。

禁用Composite时无法对窗口小部件执行任何操作的原因是Composite正在吃掉所有事件。虽然子小部件没有转发事件,但他们对父母的状态一无所知,所以他们不会变灰。

答案 2 :(得分:1)

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

  • 即使禁用控件开始,如果其控制树被禁用然后启用,它将被启用。您可能希望禁用此类控件。
  • 有时嵌套控件应在其控件树被禁用时保持启用状态。
  • 区分两种不同的禁用状态很有用:
    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控件中的活动选项卡。

答案 3 :(得分:0)

换句话说,您需要编写这样的代码,给定Composite c

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