为什么这个Java Graphics在OS X中不显示?

问题描述 投票:1回答:2

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

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
2个回答
3
投票

所以有很多问题:

Extending from JFrame

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

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

JRootPane

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

Overriding paint

作为一般规则,你应该避免重写油漆,对于大多数情况,它应该是低水平,而对于顶级容器,只是搞砸了。相反,从paintComponent开始

有关详细信息,请参阅Performing Custom PaintingPainting in AWT and Swing

Thread violations

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

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

在简单的情况下,Swing Timer更强大到足以完成这项工作。有关详细信息,请参阅How to use Swing Timers

Putting it all together...

所以,把所有这些放在一起可能最终看起来像......

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

    }

}

3
投票

在挥杆时,你不应该在挥杆线外调用挥杆动作。 Windows可以让你摆脱一些污点,但Mac上的Java对它非常挑剔。

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

不应该通过Swing线程调用animate方法,因为它调用sleep(),暂停swing线程是一个坏主意。但是,它也调用repaint(),这是一个swing调用,需要由Swing线程调用。

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

© www.soinside.com 2019 - 2024. All rights reserved.