Отключите И выделите серым цветом композицию SWT - PullRequest
13 голосов
/ 02 июня 2010

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

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

Ответы [ 4 ]

12 голосов
/ 03 июня 2010

Проблема была в том, что я отключил композит, а не элементы управления внутри него. То, что я в итоге сделал, было примерно так:

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);
   }
}
11 голосов
/ 02 июня 2010

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

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

1 голос
/ 12 ноября 2016

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

  • Даже если элемент управления отключен для запуска, он станет включенным, если его дерево элементов управления отключено, а затем включено. Вы, вероятно, хотите отключить такой элемент управления.
  • Иногда вложенные элементы управления должны оставаться включенными, когда их дерево элементов управления отключено.
  • Полезно различать два разных отключенных состояния:
    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 элементе управления.

0 голосов
/ 03 июня 2010

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

for (Control child : c.getChildren())
  child.setEnabled(false);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...