JFrame/Panel停止实例化/构造函数调用

huangapple 未分类评论46阅读模式
英文:

JFrame/Panel stops instanciation/Constructor callup

问题

这是我昨天追踪到的一个错误,从那以后一直难以真正描述清楚。

错误本身始于主方法:

  1. public static void main(String[] args) {
  2. new LogManager();
  3. new ConfigManager();
  4. new Rendering();
  5. new ScriptManager();
  6. new FileManager();
  7. new SleepManager(System.currentTimeMillis()); // <-- 在这里,就好像JVM突然停止读取代码一样
  8. }

由于我使用Eclipse,我使用断点定位了有问题的代码行。实际上,它确实到达了最后一行(new SleepManager),但是在SleepManager构造函数的方法断点从未被触发:

  1. public SleepManager(long t) {
  2. lastCheck = t;
  3. }

在该类中只有这一个构造函数。而且另外也没有任何异常。但最终我成功地将问题缩小到了Rendering类中的JFramework:

  1. public class Rendering extends JPanel implements Runnable {
  2. private static final Log LOG = new Log(Rendering.class.getSimpleName());
  3. private static GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
  4. public Rendering() {
  5. // 定义基本信息
  6. systemFullScreen_width = device.getDisplayMode().getWidth();
  7. systemFullScreen_height = device.getDisplayMode().getHeight();
  8. width = (systemFullScreen_width > 0 ? systemFullScreen_width : width);
  9. height = (systemFullScreen_height > 0 ? systemFullScreen_height : height);
  10. // 创建框架
  11. frame = new JFrame();
  12. frame.addWindowListener(new FrameClose());
  13. frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  14. frame.setSize(width, height);
  15. frame.setUndecorated(true);
  16. frame.setBackground(new Color(0.0f, 0.0f, 0.0f, 0.5f));
  17. frame.setVisible(true);
  18. frame.setTitle(" Monitor ");
  19. frame.setResizable(false);
  20. frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
  21. frame.setLocationRelativeTo(null);
  22. frame.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.<AWTKeyStroke>emptySet()); // 如果不需要,删除此行
  23. panel = this;
  24. panel.setSize(width, height);
  25. panel.setBackground(new Color(0.4f, 0.4f, 0.4f, 0.9f));
  26. // --> 这里我怀疑错误出现在这一行
  27. frame.add(panel, 0);
  28. panel.revalidate();
  29. panel.setVisible(true);
  30. // 开始渲染
  31. this.start();
  32. // frame.setAlwaysOnTop(true); // 在最后启用
  33. // 设置输入监听器
  34. frame.addKeyListener(input);
  35. frame.addMouseListener(input);
  36. frame.addMouseMotionListener(input);
  37. frame.addMouseWheelListener(input);
  38. LOG.info("Rendering started!");
  39. }
  40. }

所以在这个方法中,我实际上完成了什么(因为当我编写它时它是有效的,半透明的灰色背景仍然有效/可见)是我尝试创建一个半透明的半全屏灰色背景,以便稍后在上面渲染自己的GUI元素,也就是Graphics2D。在处理全屏/透明/轻量级容器问题时花费了很多时间,但如果有更好的解决方案,我仍然愿意尝试。

因此,被标记的这一行(frame.add(panel, 0);)似乎是问题所在,因为当我移除这一行时它能够工作(就这么简单),而且似乎这是唯一一个会导致问题的行。

panel.revalidate(); 是我最早的想法,但没有帮助,所以我决定仍然保留它。

我无法理解为什么那个在运行时已经完成的代码行会阻止另一个在下面200行处的方法被调用?有任何想法吗?


编辑1:
感谢Matt指出这些代码行实际上与主题有关:

  1. public void render(Graphics2D g2d) {
  2. while(isRunning) {
  3. renderGUI(g2d); // 这个方法什么也没做
  4. }
  5. frame.dispose();
  6. }
  7. @Override
  8. public void paintComponent(Graphics g) {
  9. super.paintComponent(g);
  10. render((Graphics2D) g);
  11. }
  12. @Override
  13. public void run() {
  14. while(isRunning) {
  15. try {
  16. frame.repaint();
  17. Thread.sleep(5);
  18. } catch(Exception e) {
  19. LOG.error(e);
  20. }
  21. }
  22. }

编辑2:

实际上将我引导到解决方案的是Matt提到的“EDT”,我之前并不知道,所以我搜索了一下并了解了什么是事件分派线程(Event Dispatch Thread)。所以现在我知道,在调用this.start启动线程之前,EDT实际上在某个时候首先调用了paintComponent方法,进入了这个我完全忽视的丑陋的子代码双循环中。老实说...我真是丢脸。谢谢Matt。

英文:

This is a bug that I tracked down yesterday and since then having a hard time to actually describe it.

The bug itself starts in the main method:

  1. public static void main(String[] args) {
  2. new LogManager();
  3. new ConfigManager();
  4. new Rendering();
  5. new ScriptManager();
  6. new FileManager();
  7. new SleepManager(System.currentTimeMillis()); &lt;-- Here it is as if the JVM just stops reading code

Since I work with eclipse I used breakpoints to locate the problematic line. And it actually reaches that last line(new SleepManager) but the method breakpoint at the SleepManager constructor is never reached:

  1. public SleepManager(long t) {
  2. lastCheck = t;

There is only that one constructor in the class. And in addition there is no exception whatsoever.
But eventually I managed to narrow it down to my JFramework in the Rendering Class:

  1. public class Rendering extends JPanel implements Runnable {
  2. private static final Log LOG = new Log(Rendering.class.getSimpleName());
  3. private static GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0];
  4. public Rendering() {
  5. //define basics
  6. systemFullScreen_width = device.getDisplayMode().getWidth();
  7. systemFullScreen_height = device.getDisplayMode().getHeight();
  8. width = (systemFullScreen_width &gt; 0 ? systemFullScreen_width : width);
  9. height = (systemFullScreen_height &gt; 0 ? systemFullScreen_height : height);
  10. //crate framework
  11. frame = new JFrame();
  12. frame.addWindowListener(new FrameClose());
  13. frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  14. frame.setSize(width, height);
  15. frame.setUndecorated(true);
  16. frame.setBackground(new Color(0.0f,0.0f,0.0f,0.5f));
  17. frame.setVisible(true);
  18. frame.setTitle(&quot; Monitor &quot;);
  19. frame.setResizable(false);
  20. frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
  21. frame.setLocationRelativeTo(null);
  22. frame.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.&lt;AWTKeyStroke&gt; emptySet()); //TODO remove if not needed
  23. panel = this;
  24. panel.setSize(width, height);
  25. panel.setBackground(new Color(0.4f,0.4f,0.4f,0.9f));
  26. --&gt; frame.add(panel, 0); //here i suspect the error
  27. panel.revalidate();
  28. panel.setVisible(true);
  29. //start rendering
  30. this.start();
  31. //frame.setAlwaysOnTop(true); //TODO enable at the end
  32. //set input listeners
  33. frame.addKeyListener(input);
  34. frame.addMouseListener(input);
  35. frame.addMouseMotionListener(input);
  36. frame.addMouseWheelListener(input);
  37. LOG.info(&quot;Rendering started!&quot;);
  38. }

Ok so what I actually did accomplish in that method (since it worked when I wrote it and the transparent grey background is still working/visible) is that I try to create a half-transparent semi-fullscreen grey background to later render my own GUI element on it aka Graphics2D. Had rough time working around the fullscreen/transparency/lightweight container problem but still open for better solutions if someone has them.

So the marked line(frame.add(panel, 0);) seems to be the problem because it works when I remove the line (simple as that) and it seems to be the only line that does so.

The panel.revalidate(); was my first idea it did not help, jet i decided to keep it anyway.

Can't wrap my head around why that one line that was already done by runtime should stop another method, 200 lines beneath from being called? Any ideas?


Edit1:
Thanks to Matt who pointed out that these code lines are indeed somehow important to the subject:

  1. public void render(Graphics2D g2d){
  2. while(isRunning){
  3. renderGUI(g2d); //this method does nothing jet its empty
  4. }
  5. frame.dispose();
  6. }
  7. @Override
  8. public void paintComponent(Graphics g) {
  9. super.paintComponent(g);
  10. render((Graphics2D) g);
  11. }
  12. @Override
  13. public void run() {
  14. while(isRunning){
  15. try{
  16. frame.repaint();
  17. Thread.sleep(5);
  18. }catch(Exception e){
  19. LOG.error(e);
  20. }
  21. }
  22. }

Edit2:

What actually led me to the solution: Matt mentioned "EDT" what I didn't knew so I googled it and learn what the Event Dispatch Thread is. So now I knew, before this.start to start the thread gets called, the EDT actually at some point calls the paintComponent method first and enters this ugly child-code doubleloop-ception that I totally overlooked. Honestly... Shame on me. Thx Matt.

huangapple
  • 本文由 发表于 2020年7月23日 14:26:24
  • 转载请务必保留本文链接:https://java.coder-hub.com/63048145.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定