(Java) Появление / исчезновение JLabel в JPanel исчезает только при изменении размера - PullRequest
0 голосов
/ 03 июня 2009

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

Ответы [ 2 ]

7 голосов
/ 03 июня 2009

Как правило, вызова метода 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 пытается внести изменения в GUI. (Как примечание, метод repaint является поточно-ориентированным, поэтому его можно вызывать потоками вне EDT, но использование repaint - это обходной путь, а не решение.)

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

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

Итак, предыдущий 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.

2 голосов
/ 03 июня 2009

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

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

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

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

...