【问题标题】:Why doesn't this Java Graphics display in OS X?为什么这个 Java 图形在 OS X 中不显示?
【发布时间】:2018-04-19 08:29:32
【问题描述】:

我在课堂上获得了一些演示代码,这些代码在实验室的 Windows 计算机上运行,​​但在我的 2010 MacBook(使用 Sierra)上运行方式不同。

进行Java Graphics Not Displaying In OS X 中建议的更改并没有解决我的问题。我也尝试过调整窗口大小,这会稍微改变动画——调整大小后它会间歇性地弹出。如果我增加 Thread.sleep() 时间并调整大小,则动画会改善,但仍然不稳定。

为什么代码在我的 MacBook 上不起作用?我怎样才能让它起作用?

原始代码(适用于 Windows 10 但不适用于我的 Mac):

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GraphicsTestA extends JFrame{
   int x1 = 60;
   int x2 = 150;
    public static void main(String [] args){
        GraphicsTestA gta = new GraphicsTestA();
      gta.animate();
    }

   private void animate()
   {
      while(true)
      {
         for(int i=0; i <100; i ++)
         {
            x1 = x1 + 1;
            x2 = x2 - 1;
            try
            {
               Thread.sleep(100);
            }
            catch(Exception ex)
            {}
            repaint();
         }

         x1 = 60;
         x2 = 150;
      }
   }
    public GraphicsTestA() {
        setSize(200,200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        this.validate();
    }

    public void paint(Graphics g) {
        super.paint(g);

      g.drawString("Hello World",80,80);
      g.drawLine(x1,60,x2,150);
        g.drawRect(100,40,30,30);

    }
}

【问题讨论】:

    标签: java windows macos swing graphics2d


    【解决方案1】:

    所以有很多问题:

    JFrame扩展

    通常不鼓励直接从像 JFrame 这样的顶级容器扩展,因为您很少向其中添加任何新的可重用功能,并且它会将您锁定在单个用例中。

    它也是一个复合组件,也就是说,它上面有许多组件,这是导致问题的主要原因之一。

    相反,从JPanel 之类的内容开始,然后将其添加到您需要的任何其他容器中。

    覆盖paint

    作为一般规则,您应该避免覆盖绘画,在大多数情况下它是低级的,而对于顶级容器,只会把事情搞砸。而是从paintComponent开始

    更多详情请参阅Performing Custom PaintingPainting in AWT and Swing

    线程违规

    正如已经指出的,Swing 不是线程安全的,它是单线程的。

    这意味着您永远不应从事件调度线程之外更新 UI 或 UI 依赖的任何值。这也意味着您也不应该在 EDT 的上下文中执行任何长时间运行或阻塞的操作。

    在简单的情况下,Swing Timer 功能强大到足以胜任这项工作。详情请见How to use Swing Timers

    把它们放在一起......

    因此,将所有这些放在一起可能最终看起来像......

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import static javax.swing.JFrame.EXIT_ON_CLOSE;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class GraphicsTestA {
    
        public static void main(String[] args) {
            new GraphicsTestA();
        }
    
        public GraphicsTestA() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            int x1 = 60;
            int x2 = 150;
            int loops = 0;
    
            public TestPane() {
                Timer timer = new Timer(100, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        x1 = x1 + 1;
                        x2 = x2 - 1;
                        loops++;
                        if (loops > 100) {
                            x1 = 60;
                            x2 = 150;
                            ((Timer) e.getSource()).stop();
                        }
                        repaint();
                    }
                });
                timer.start();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.drawString("Hello World", 80, 80);
                g2d.drawLine(x1, 60, x2, 150);
                g2d.drawRect(100, 40, 30, 30);
                g2d.dispose();
            }
    
        }
    
    }
    

    【讨论】:

    • 感谢您的详细回答。不过,我无法让您的代码显示动画。框架是空白的。
    • 我在我的 Mac 上编写并运行它没有问题。我也刚刚在我的 MacBook Pro 上进行了测试,没有出现问题
    • 你有哪个版本的java?
    • 应该没什么区别,但我目前正在使用1.8.0_131
    • 我同意它不应该有所作为......但我不明白完全相同的代码如何在我的笔记本电脑上不起作用 D:
    【解决方案2】:

    在swing 中,您不应该在swing 线程之外调用swing 事物。 Windows 可以让你摆脱一些麻烦,但 Mac 上的 Java 对此非常挑剔。

    在这段代码中,构造函数进行了swing调用,但它是从主线程调用的。您可以尝试将其拆分,以便 Swing 线程调用构造函数,但是 animate 方法存在问题。

    不应由 Swing 线程调用 animate 方法,因为它正在调用 sleep(),并且暂停 swing 线程是个坏主意™。但是,它也调用了repaint(),这是一个swing调用,需要被Swing线程调用。

    我建议你使用EventQueue.invokeLater 来构建你的窗口,然后弄清楚如何使用 Swing Workers 或其他一些合适的机制来做你的动画。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-12
      • 1970-01-01
      • 2011-01-22
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多