2010-06-02 3 views
12

У меня есть Composite, который я хочу, чтобы иметь возможность включать/отключать программно. Метод Control.setEnabled(boolean enabled) работает нормально, но он не дает никакой визуальной информации о том, что виджеты (-ы) отключены.Disable AND gray out SWT composite

Что я хотел бы сделать, так это то, что состояние отключено означает, что виджеты выделены серым цветом. Сейчас они просто вводят странное состояние, когда пользователь не может щелкнуть или выполнить какое-либо действие над ними.

ответ

10

A Composite - это элемент управления контейнером, в котором используются другие элементы управления с использованием макета - вы не можете видеть композит на самом деле, вы можете видеть только те элементы управления, которые он удерживает. Чтобы отключить и визуально увидеть, затем отключить, вам нужно будет позвонить setEnabled(false) всем детям, при условии, что они также не являются контейнерами. В принципе, нужно включить/отключить виджеты листа, и вы увидите визуальную индикацию.

Причина, по которой вы ничего не можете сделать с виджетами при отключении Composite, заключается в том, что Composite ест все события. Хотя дочерние виджеты не передают события, они ничего не знают о состоянии своего родителя, поэтому они не выделены серым цветом.

0

Другими словами, вам нужно написать код, как это, учитывая Composite c:

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

На самом деле, вам не нужно восстанавливать весь контрольный стек.Это не сработает, если вы скажете, что у вас есть створка в композите, а ваши виджеты находятся в створке. – andyczerwonka

+0

Да, я знаю. Я просто привел пример. – dplass

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

Еще одна настройка для сообщения Фредрика, в основном это то, что мне нужно. У меня есть ситуация, когда есть вкладки и некоторые другие типы композитов, которые необходимо отключить в дополнение к отключению их детей. Итак: ' ... для (Control C: comp.getChildren()) recursiveSetEnabled (с, включена); comp.setEnabled (включено); ... ' – 2011-03-05 23:45:00

+0

Это также полезно для отключения дерева элементов управления, но исключая определенные элементы управления, которые невозможно использовать, например. Composite ... отключить(), а затем попытаться снова включить определенные элементы управления. – Gregor

+0

Но когда вы снова включаете виджеты, вы хотите, чтобы ранее отключенные были отключены. С помощью этого решения вы включите все. – Lii

0

Другие решения, размещенные здесь, довольно примитивны. У них есть несколько недостатков:

  • Даже если элемент управления отключен для начала, он станет включен, если его дерево управления будет отключено и затем активировано. Вероятно, вы хотите отключить такой контроль.
  • Иногда вложенные элементы управления должны оставаться включенными, когда их дерево управления отключено.
  • Полезно различать между двумя различными состояниями инвалидов:
    1. неактивное состояние, без информации, чтобы показать. Это должно быть визуально указано пользователю.
    2. Отображение информации, но только для чтения. Полезно иметь возможность копировать текст в текстовые поля в этом состоянии.

Код ниже решает эти проблемы. Это идеальный помощник/дезабер для SWT.

Он отслеживает измененные элементы управления, помечая их Widget.setData, так что он позволяет использовать только те блоки, которые он ранее отключил. Он обрабатывает различные типы элементов управления по-разному в состояниях дерева: DISABLED, READ_ONLY и 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); 
     } 
    } 
} 

Одно ограничение в том, что даже в отключенном состоянии все еще можно изменить активную вкладку в TabFolder управления.

Смежные вопросы