2010-06-02 53 views
12

我有一個Composite,我希望能夠以編程方式啓用/禁用。 Control.setEnabled(boolean enabled)方法可以正常工作,但它不會給出任何關於窗口小部件被禁用的視覺信息。禁用並灰掉SWT複合

我想要做的是讓殘疾人狀態意味着小部件變灰。現在他們只是進入一個奇怪的狀態,用戶無法點擊或執行任何操作。

回答

10

Composite是一個容器控件,它使用佈局來保存其他控件 - 你看不到真正的複合,你只能看到它所持有的控件。要禁用和可視化查看然後禁用,您必須在所有子級上調用setEnabled(false),假設它們不是容器。基本上,必須啓用/禁用葉子小部件,您將看到可視指示。

禁用Composite時無法對小部件做任何事情的原因是因爲Composite正在吃所有的事件。雖然孩子的小工具沒有得到轉發的事件,但他們對父母的狀態一無所知,所以他們不會灰心。

0

換句話說,你需要寫這樣的代碼,給定一個Composite c

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

不是真的 - 你需要遞減整個控制堆棧。如果說你在一個組合中有一個窗框,並且你的小部件在窗框中,這將不起作用。 – andyczerwonka 2010-06-03 04:21:14

+0

是的,我知道。我只是舉一個例子。 – dplass 2010-06-03 12:09:21

11

問題的確,我是禁用的合成,而不是控制它裏面。我落得這樣做是這樣的:

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

Fredrik的帖子還有一個額外的調整,主要是我所需要的。我有一種情況,那就是除了禁用孩子之外,還需要禁用選項卡和其他一些類型的組合。 所以: ' ... 的(控制C:comp.getChildren()) recursiveSetEnabled(C,啓用); comp.setEnabled(enabled); ... ' – 2011-03-05 23:45:00

+0

這對於禁用控件樹也是有用的,但排除某些控件,這是不可能的,例如,複合...禁用(),然後嘗試重新啓用某些控件。 – Gregor 2012-12-13 11:20:08

+0

但是,當您重新啓用小部件時,您希望將先前禁用的小部件保留爲禁用狀態。有了這個解決方案,您將啓用一切。 – Lii 2016-09-16 12:37:46

0

張貼在這裏的其他解決方案是相當原始。他們有幾個缺點:

  • 即使控制被禁用,開始時,如果控件樹被禁用它將會啓用然後啓用。你可能想保持禁用這樣的控制。
  • 有時,嵌套控件在其控件樹被禁用時應保持啓用狀態。
  • 區分兩種不同的禁用狀態是有用的:
    1. 禁用狀態,沒有要顯示的信息。這應該清楚地向用戶顯示。
    2. 顯示信息,但只讀狀態。能夠在此狀態下複製文本字段中的文本很有用。

下面的代碼解決了這些問題。 這是SWT的最終啓用者/禁用者。

它通過標記Widget.setData來追蹤修改後的控件,以便它只啓用之前禁用的控件。它在樹狀態中處理不同類型的控件:DISABLED,READ_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控制活動選項卡。