(Java) Появление/исчезновение JLabel в JPanel исчезает только при изменении размера

Я работаю на Java, и у меня есть JPanel в JFrame. В этом JPanel, среди прочего, у меня есть JLabel, который я хочу заставить появляться и исчезать по желанию. Я пытался установить видимость в значение true/false, добавляя и удаляя его из JFrame и JPanel, и, посмотрев в Интернете, я пробовал проверять() и повторно проверять() до бесконечности. Что здесь можно сделать, чтобы решить эту проблему?


person user116330    schedule 03.06.2009    source источник
comment
Пробовали ли вы вызывать repaint() для JLabel или его родительских компонентов?   -  person rodion    schedule 03.06.2009


Ответы (2)


Как правило, вызова метода setVisible достаточно, чтобы показать или скрыть компонент Swing.

Чтобы убедиться, что это работает, я попробовал следующее:

public class Visibility {
  private void makeGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    final JLabel l = new JLabel("Hello");
    final JButton b = new JButton("Hide Label");
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        l.setVisible(false);
      }
    });

    f.getContentPane().setLayout(new BorderLayout());
    f.getContentPane().add(l, BorderLayout.CENTER);
    f.getContentPane().add(b, BorderLayout.SOUTH);
    f.setSize(200, 200);
    f.setLocation(200, 200);
    f.validate();
    f.setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Visibility().makeGUI();
      }
    }); 
  }
}

Вышеупомянутая программа может влиять на видимость, нажав на значок JButton.

Может ли это быть проблема с потоками?

Мое следующее подозрение заключалось в том, что, возможно, Thread отсутствует в событии поток отправки (EDT) может не влиять на отображение немедленно, поэтому я добавил следующее после инициализации JLabel и JButton.

Thread t = new Thread(new Runnable() {
  public void run() {
    while (true) {
      b.setVisible(!b.isVisible());

      try {
        Thread.sleep(100);
      } catch (InterruptedException e) { /* Handle exception /* }
    }
  }
});

t.start();

С новым запущенным Thread он менял видимость JLabel каждые 100 мс, и это также работало без проблем.

Вызов компонента Swing из потока диспетчеризации событий (EDT) — это плохо, поскольку Swing не является потокобезопасным. Я был немного удивлен, что это работает, и то, что это работает, может быть просто случайностью.

Перекрасить JPanel?

Если видимость JLabel изменяется только при изменении размера, это, вероятно, означает, что JLabel рисуется только тогда, когда JPanel перерисовывается.

Одна вещь, которую можно попробовать, это вызвать функцию JPanel repaint, чтобы увидеть, изменится ли видимость JLabel.

Но этот метод кажется просто бинтом в ситуации, если основная причина связана с тем, что поток вне EDT пытается внести изменения в графический интерфейс. (Как примечание, метод repaint является потокобезопасным, поэтому его можно вызывать из потоков вне EDT, но полагаться на repaint — это обходной путь, а не решение.)

Попробуйте использовать SwingUtilities.invokeLater

Наконец, вероятно, я бы попробовал SwingUtilities.invokeLater, который можно вызывать (и следует вызывать только) из потока, работающего отдельно от EDT, если он хочет повлиять на графический интерфейс.

Таким образом, предыдущий пример Thread следует записать так:

Thread t = new Thread(new Runnable() {
  public void run() {
    while (true) {
      try {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            b.setVisible(!b.isVisible());
          }
        });
      } catch (Exception e1) { /* Handle exception */ }

      try  {
        Thread.sleep(100);
      } catch (InterruptedException e) { /* Handle exception */ }
    }
  }
});

t.start();

Если изменение графического интерфейса действительно происходит в отдельном потоке, я бы рекомендовал прочитать Урок: Параллелизм в Swing из Руководства по Java чтобы узнать больше информации о том, как писать хорошо работающий многопоточный код с помощью Swing.

person coobird    schedule 03.06.2009

setVisible() или его удаление должно работать нормально, однако убедитесь, что вы делаете это из потока отправки событий. В EventQueue есть служебные методы для запуска блоков в этом потоке.

http://helpdesk.objects.com.au/java/how-do-i-update-my-gui-from-any-thread

Вам нужно будет вызвать revalidate() на родительской панели JPanel, если вам нужно перекомпоновать ее компоненты.

Если вы можете опубликовать пример, демонстрирующий проблему, я могу взглянуть на нее для вас.

person objects    schedule 03.06.2009