【问题标题】:(Java) Appearing/Disappearing JLabel in a JPanel only disappears on resize(Java) 在 JPanel 中出现/消失的 JLabel 仅在调整大小时消失
【发布时间】:2009-06-03 03:04:42
【问题描述】:

我正在使用 Java,并且在 JFrame 中有一个 JPanel。在那个 JPanel 中,我有一个 JLabel,我想让它随意出现和消失。我尝试将可见性设置为真/假,在 JFrame 和 JPanel 中添加和删除它,并且在网上查看后,我尝试无限期地验证()和重新验证()。在这里可以做些什么来解决这个问题?

【问题讨论】:

  • 您是否尝试过在 JLabel 或其父组件上调用 repaint()?

标签: java resize jframe jpanel repaint


【解决方案1】:

一般来说,调用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来影响可见性。

可能是线程问题吗?

我的下一个怀疑是,可能不在event dispatch thread (EDT) 上的Thread 可能不会立即影响显示,所以我在初始化JLabelJButton 后添加了以下内容。

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 运行,它每 100 毫秒更改一次 JLabel 的切换可见性,这也没有问题。

event dispatch thread (EDT) 中调用 Swing 组件是一件坏事,因为 Swing 不是线程安全的。我有点惊讶它起作用了,它起作用的事实可能只是侥幸

重绘JPanel?

如果 JLabel 的可见性仅在调整大小时受到影响,则可能意味着仅在重新绘制 JPanel 时才绘制 JLabel

可以尝试的一件事是调用JPanelrepaint 方法来查看JLabel 的可见性是否会改变。

但是这种方法似乎只是一种创可贴,如果主要原因是由于 EDT 试图更改 GUI 的线程而导致的。 (请注意,repaint 方法是线程安全的,因此可以由非 EDT 线程调用,但依赖 repaint 是一种变通方法而不是解决方案。)

尝试使用SwingUtilities.invokeLater

最后,我可能会尝试使用SwingUtilities.invokeLater 方法,如果它想影响 GUI,可以从与 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();

如果对 GUI 的更改确实发生在单独的线程上,那么我建议阅读 The Java Tutorials 中的 Lesson: Concurrency in Swing,以了解有关如何使用 Swing 编写表现良好的多线程代码的更多信息。

【讨论】:

    【解决方案2】:

    setVisible() 或删除它应该可以正常工作,但请确保您是从事件调度线程中进行的。 EventQueue 中有一些实用方法用于在该线程中运行块。

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

    如果您需要重新布局父 JPanel 的组件,则需要在父 JPanel 上调用 revalidate()。

    如果您可以发布一个演示问题的示例,我可以为您查看。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-09
      • 1970-01-01
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多