(Java) JPanel 中出现/消失的 JLabel 仅在调整大小时消失

发布于 2024-07-22 03:46:46 字数 196 浏览 5 评论 0原文

我正在使用 Java,并且 JFrame 中有一个 JPanel。 在该 JPanel 中,除其他外,我有一个 JLabel,我想让它随意出现和消失。 我尝试将可见性设置为 true/false,在 JFrame 和 JPanel 中添加和删除它,并且在网上查看后,我尝试了无限次的 validate() 和 revalidate() 。 这里可以做什么来解决这个问题呢?

I'm working in Java, and I have a JPanel in a JFrame. In that JPanel, among other things, I have a JLabel that I want to make appear and disappear at will. I've tried setting visibility to true/false, adding and removing it from the JFrame and JPanel, and, having looked online, I tried validate()ing and revalidate()ing ad infinitum. What can be done here to solve this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

那片花海 2024-07-29 03:46:46

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

这可能是线程问题吗?

我的下一个怀疑是,线程可能不在事件调度线程 (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 的运行,它每 100 毫秒更改一次 JLabel 的可见性,而且这也没有问题。

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

重新绘制 JPanel

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

要尝试的一件事是调用 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 的更改确实发生在单独的线程上,那么我建议阅读 课程:Swing 中的并发 来自 Java 教程,以了解有关如何使用 Swing 编写性能良好的多线程代码的更多信息。

In general, calling the setVisible method is sufficient to make a Swing component to be shown or hidden.

Just to be sure that it works, I tried the following:

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();
      }
    }); 
  }
}

The above program is able to affect the visibility by clicking on a JButton.

Could it be a Threading Issue?

My next suspicion was that perhaps a Thread that is not on the event dispatch thread (EDT) may not be affecting the display immediately, so I added the following after initializing the JLabel and 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();

With the new Thread running, it changed the toggled the visibility of the JLabel every 100 ms, and this also worked without a problem.

Calling a Swing component off the event dispatch thread (EDT) is a bad thing, as Swing is not thread-safe. I was a little surprised it worked, and the fact that it works may just be a fluke.

Repaint the JPanel?

If the JLabel's visibility is only being affected on resizing, it probably means that the JLabel is being drawn only when the JPanel is being repainted.

One thing to try is to call the JPanel's repaint method to see if the visibility of the JLabel will change.

But this method seems to be just a band-aid to a situation, if the main cause is due to a thread off the EDT is attempting to make changes to the GUI. (Just as a note, the repaint method is thread-safe, so it can be called by off-EDT threads, but relying on repaint is a workaround than a solution.)

Try using SwingUtilities.invokeLater

Finally, probably the thing I would try is the SwingUtilities.invokeLater method, which can be called (and should only be called) from a thread running separate from the EDT, if it wants to affect the GUI.

So, the earlier Thread example should be written as:

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();

If the change to the GUI is indeed occurring on a separate thread, then I would recommend reading Lesson: Concurrency in Swing from The Java Tutorials in order to find out more information on how to write well-behaving multi-threaded code using Swing.

笛声青案梦长安 2024-07-29 03:46:46

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

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

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

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

setVisible() or removing it should work fine, make sure you are doing it from the event dispatch thread though. There are utility methods in EventQueue for running blocks in that thread.

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

You would need to call revalidate() on the parent JPanel if you need its components to be re-laid out.

If you can post an example that demonstrates the problem I can have a look at it for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文