Проблема прозрачности с оверлейной панелью

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

Что ж, у меня есть следующая проблема: в общем, я хотел бы «затенить» некоторый контент (точнее, контент JPanel). Мне почти удалось добиться желаемого эффекта, поместив еще одну панель JPanel, «растекающуюся» по нужной области с прозрачным цветом. Однако осталась одна серьезная проблема: как только я сделал панель наложения видимой, компоненты ниже сразу не будут отображаться правильно. Вместо этого они сначала будут окрашены каким-то белым цветом, пока, например, я не уменьшу и не разверну рамку, что приведет к правильному отрисовке эффекта прозрачности.

В качестве примера приложил скриншот внешнего вида "глюка". Обратите внимание на переключатели и флажки, которые выглядят белыми. Кроме того, я прикрепил код для воспроизведения эффекта. В настоящее время я работаю над Windows 7, 32-битной версией Java 1.5. (Java 1.6 не имеет никакого значения).

Я много играл с различными функциями paint()/repaint()/(in/re)validate()/etc. методы. Ничего не помогло правильно нарисовать панель наложения сразу после того, как она стала видимой.

Есть идеи?

БР, Крис

EDIT1: Что касается примера кода - если вы запустите его, вам нужно нажать кнопку «Проверить», чтобы вызвать панель наложения. :) Еще одна вещь, которую я заметил, это то, что проблемы с внешним видом различаются в зависимости от используемого интерфейса L&F. В моем случае я использовал один раз Windows и один раз собственный интерфейс Java (это называется металл?), и они показали разные результаты, хотя ни один из них не работал должным образом: P

Ссылка на снимок экрана с ошибкой: Снимок экрана

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.miginfocom.swing.MigLayout;

public class MigTest {
  public static void main(String[] args) {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.add(new TestLayeredPane());
    f.pack();
    f.setVisible(true);
  }
  public static class TestLayeredPane extends JPanel {
    private JPanel pnl_overlay_;

public TestLayeredPane() {
  super();
  this.setLayout(new MigLayout("fill, wrap 2", "", ""));

  initLayout();
}
private void initLayout() {
  JPanel pnl_direction = new JPanel(new MigLayout("wrap 3", "", ""));
  JPanel pnl_settings = new JPanel(new MigLayout("wrap 1", "", ""));
  JPanel pnl_input = new JPanel(new MigLayout("wrap 3", "", ""));

  JLabel lbl_ask_for = new JLabel();
  JLabel lbl_translation = new JLabel();

  ButtonGroup btn_group_ = new ButtonGroup();
  JRadioButton radiobtn_ask_lang1_ = new JRadioButton();
  JRadioButton radiobtn_ask_lang2_ = new JRadioButton();
  JRadioButton radiobtn_ask_random_ = new JRadioButton();

  JCheckBox chkbox_loop_ = new JCheckBox();
  JCheckBox chkbox_repeat_false_ = new JCheckBox();
  JCheckBox chkbox_letter_count_ = new JCheckBox();
  JCheckBox chkbox_ask_all_ = new JCheckBox();

  JLabel lbl_progress_ = new JLabel();
  JLabel lbl_question_ = new JLabel();

  JButton btn_check_ = new JButton();
  JButton btn_push_back_ = new JButton();

  JTextField tfield_answer_ = new JTextField();

  /** Customize all elements of our layout **/
  lbl_ask_for.setText("Ask for:");

  lbl_translation.setText("translation");

  radiobtn_ask_lang1_.setText("1st language");
  radiobtn_ask_lang2_.setText("2nd language");
  radiobtn_ask_random_.setText("Random language");

  btn_group_.add(radiobtn_ask_lang1_);
  btn_group_.add(radiobtn_ask_lang2_);
  btn_group_.add(radiobtn_ask_random_);

  chkbox_loop_.setText("Loop");
  chkbox_repeat_false_.setText("Repeat false answers");
  chkbox_letter_count_.setText("Show letter count");
  chkbox_ask_all_.setText("Ask for 1st and 2nd language");

  btn_check_.setText("Check");
  btn_check_.addActionListener(new ActionListener() {

    public void actionPerformed(ActionEvent e) {
      finishTraining();
    }
  });

  btn_push_back_.setText(" Push back");

  /** Add all elements to this panel **/
  pnl_direction.add(lbl_ask_for, "span 1 3");
  pnl_direction.add(radiobtn_ask_lang1_);
  pnl_direction.add(lbl_translation, "span 1 3");
  pnl_direction.add(radiobtn_ask_lang2_);
  pnl_direction.add(radiobtn_ask_random_);

  pnl_settings.add(chkbox_loop_);
  pnl_settings.add(chkbox_repeat_false_);
  pnl_settings.add(chkbox_letter_count_);
  pnl_settings.add(chkbox_ask_all_);

  pnl_input.add(lbl_question_, "align center");
  pnl_input.add(lbl_progress_, "span 2, align center");
  pnl_input.add(tfield_answer_, "span 1 2, align center, w 200!");
  pnl_input.add(btn_check_, "growy");
  pnl_input.add(btn_push_back_);

  pnl_overlay_ = new JPanel(new MigLayout("fill", "", ""));
  pnl_overlay_.setBackground(new Color(127, 127, 127, 100));
  this.add(pnl_overlay_, "pos (0%+2px) (0%+2px) (100%-2px) (100%-2px) ");
  pnl_overlay_.setVisible(false);

  this.add(pnl_direction, "gapbefore push");
  this.add(pnl_settings, "gapafter push");
  this.add(pnl_input, "span 2, gapbefore push, gapafter push");
}

private void finishTraining() {
  //disable all visible items in the content area
  for (Component comp : this.getComponents()) {

    if (comp instanceof JPanel) {
      for (Component comp2 : ((JPanel) comp).getComponents()) {
        comp2.setEnabled(false);
      }
    }
    else {
      comp.setEnabled(false);
    }
  }
  pnl_overlay_.setVisible(true);
}
  }
}

person ChristianS    schedule 12.09.2010    source источник
comment
привет всем .... Этому вопросу уже почти ДВА года. Ну давай же!   -  person will    schedule 27.08.2012
comment
Я только начал искать подходящий класс: JLayersPanel, который будет наследоваться от JPanel. Эта модель будет использовать код JLayeredPane в качестве шаблона. Предложения приветствуются, потому что это важно для дизайна, который я хочу создать.   -  person will    schedule 27.08.2012


Ответы (1)


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

Рекурсивный вариант прост, если вам не нужно отслеживать предыдущее включенное состояние всех дочерних элементов и восстанавливать их, когда вы хотите снова включить родительский контейнер. Такая функция сделает это:

static void setChildrenEnabled(Container root, boolean enable)
{
    Component children[] = root.getComponents();
    for(int i = 0; i < children.length; i++)
    {
        children[i].setEnabled(enable);
        if(children[i] instanceof Container)
        {
            setChildrenEnabled((Container) children[i], enable);
        }          
    }
}

Для такого подхода, как ваш, я нашел довольно хорошую публикацию с достойным объяснением подводных камней и исходным кодом, который вы можете найти здесь: http://tips4java.wordpress.com/2009/08/02/disabled-panel/

Я надеюсь, что там есть что-то, что поможет.

person Arnold Spence    schedule 12.09.2010
comment
Итак: 1) отключение (setEnabled(false)) на самом деле не проблема. Вы упомянули подход, который при необходимости можно было бы подкрепить картой для сохранения исходного состояния. 2) проблема со стеклянной панелью - AFAIK - заключается в том, что она доступна только для корневых панелей и охватывает все контейнеры в пределах своей иерархии сдерживания. таким образом, в моем случае у меня возникнут проблемы, потому что я использую JInternalFrame, добавленный к всплывающему слою многослойной панели JFrame, которая будет ниже стеклянной панели. - person ChristianS; 13.09.2010
comment
Я попробовал ваш код и могу подтвердить поведение. Я также могу подтвердить, что это, похоже, напрямую связано с MigLayout. Если я уберу все его использование и поставлю все, скажем, в потоковую компоновку, наложение будет выглядеть правильно. Завтра поиграю, может что получится :) - person Arnold Spence; 13.09.2010
comment
очень любезно, спасибо! я бился головой о стену, пытаясь решить эту проблему, но безуспешно. может какие-то свежие идеи помогут найти решение :) - person ChristianS; 13.09.2010
comment
Я пробовал кучу вещей, вероятно, то же самое, что и вы, но безрезультатно. - person Arnold Spence; 14.09.2010
comment
самое смешное, что это нормально после, например. свернуть/развернуть... :/ - person ChristianS; 14.09.2010