我在课堂上给了一些演示代码,这些代码在实验室的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);
}
}
答案 0 :(得分:3)
在挥杆时,你不应该在挥杆线外调用挥杆动作。 Windows可以让你摆脱一些污点,但Mac上的Java对它非常挑剔。
在这段代码中,构造函数进行了swing调用,但它是从主线程调用的。您可以尝试将其拆分,以便Swing线程调用构造函数,但是animate方法存在问题。
Swing线程不应该调用animate方法,因为它调用了sleep()
,暂停swing线程是一个坏主意。但是,它也调用repaint()
,这是一个swing调用,需要由Swing线程调用。
我建议您使用EventQueue.invokeLater
构建窗口,然后弄清楚如何使用Swing Workers或其他适当的机制来制作动画。
答案 1 :(得分:3)
所以有很多问题:
JFrame
通常不鼓励直接从顶级容器(例如JFrame
)扩展,因为您很少向其添加任何新的可重用功能,并且它会将您锁定到单个用例中。
它也是一个复合组件,也就是说,它上面有许多组件,这是造成问题的主要原因之一。
相反,从JPanel
开始,然后将其添加到您需要的任何其他容器中。
paint
作为一般规则,你应该避免重写油漆,在大多数情况下它应该是低水平,而在顶级容器的情况下,只是搞砸了。相反,请从paintComponent
有关详细信息,请参阅Performing Custom Painting和Painting 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();
}
}
}