Blinking in JFrame Java



大家好,我正在做一个线程来更新JFrame上的球,所以我重新绘制了屏幕。。。然后绘制球更新其位置。。然后再次绘制屏幕。。。把球和同样的循环。。。这是代码

private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
Thread t = new Thread()
{
public void run()
{
while(true)
{
repaint();
b2.update(ob,2);
b2.paint(ob.getGraphics());
b2.setT(b2.getT() + 1);
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
System.out.println("Error in Sleeping");
}
}
}
};
t.start();
}

但问题是我看不到球。。。屏幕上的油漆总是覆盖球,球就像在Jframe下面一样。。

如果您想在Swing中使用动画,建议使用javax.swing.Timer类。此类允许您定期对事件调度线程执行操作。

  • SwingTimer教程
  • SO上发布的动画示例(链接到SO btw上的Swing wiki中)

一些一般规则

  • Swing不是线程安全的,您应该只在事件调度线程的上下文中更新UI组件
  • 您不控制绘制过程,重新绘制管理器控制。您可以通过调用repaint来请求进行更新,但在尝试更新显示时,不应直接调用updatepaint
  • 绘制子系统使用的Graphics上下文是一个共享资源,不能保证在绘制周期之间是相同的,您永远不应该维护对它的引用。您也不应该依赖JComponent#getGraphics的结果。此方法能够返回null

示例解决方案

你有很多选择,这取决于你最终想要实现的目标。

你可以使用SwingWorker,但考虑到你要进入的是一个无限循环,而且使用SwingUtilities#invokeLater比实际使用publish方法更容易,这种方法实际上会做更多的工作。

您也可以使用Thread,但最终会遇到与使用SwingWorker相同的问题

Simplipset解决方案实际上是一个javax.swing.Timer

public class Blinky {
public static void main(String[] args) {
new Blinky();
}
public Blinky() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new BlinkyPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class BlinkyPane extends JPanel {
private JLabel blinkyLabel;
private boolean blink = false;
public BlinkyPane() {
setLayout(new GridBagLayout());
blinkyLabel = new JLabel("I'm blinking here");
blinkyLabel.setBackground(Color.RED);
add(blinkyLabel);
Timer timer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
blink = !blink;
if (blink) {
blinkyLabel.setForeground(Color.YELLOW);
} else {
blinkyLabel.setForeground(Color.BLACK);
}
blinkyLabel.setOpaque(blink);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
}
}

您可以查看Swing中的Swing Timer和Concurrency以了解更多信息

如果您访问EDT(事件调度线程)之外的GUI组件,则可能会遇到奇怪的问题。相反,如果您在EDT中执行长时间运行的任务,则也会遇到问题。

查看这篇文章了解更多关于GUI Threading in Java的信息

最新更新