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

StackOverflow https://stackoverflow.com/questions/942883

Вопрос

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

Это было полезно?

Решение

В общем, называя 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's repaint метод, позволяющий проверить, является ли видимость JLabel изменится.

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

Другие советы

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top