Java Applet - 阻止其他线程更改图形颜色

时间:2018-06-15 22:19:07

标签: java applet awt

作为学校项目的一部分,我们必须使用Applet创建一个小游戏。我现在正在进行一些测试,但有一点我无法理解: 我希望在Applet屏幕上同时在屏幕上显示多个对象。通过绘制对象,删除它然后在一段时间后移动它来创建动画效果。

这是我的代码: Robotworld课程     包核心;

import items.Obstacle;

import java.applet.Applet;
import java.awt.*;
import java.util.ArrayList;

public class Roboterwelt extends Applet {

    private ArrayList<Obstacle> obstacles = new ArrayList<>();

    @Override
    public void init() {
        setSize(600, 600);
        Graphics g = getGraphics();
        g.setColor(Color.BLACK);
        for(int x = 0; x < 5; x++) {
            Obstacle h = new Obstacle((x+1)*100, 100, g, this);
            obstacles.add(h);
            Thread t = new Thread(h);
            t.start();
        }
    }

    @Override
    public void paint(Graphics g) {
        for(Obstacle o : obstacles) {
            o.draw();
        }
    }

}

障碍课     包装物品;

import java.applet.Applet;
import java.awt.*;

public class Obstacle implements Runnable {

    private int x;
    private int y;

    private Graphics g;

    public Hindernis(int x, int y, Graphics g) {
        this.x = x;
        this.y = y;
        this.g = g;
    }    

    public void draw() {
        g.drawOval(x, y, 50, 50);   //Draw obstacle
    }

    //Deleting the obstacle by covering it with a white circle
    public void delete() {
        g.setColor(Color.WHITE); //Change the color to white
        g.fillOval(x-5,y-5,60,60); //Making it a bit bigger than the obstacle to fully cover it
        g.setColor(Color.BLACK); //Reset the color to black
    }

    @Override
    public void run() {
        try {
            while(y < 600) {
                delete();
                y += 10;
                draw();
                Thread.sleep(1000);
            }
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

}

问题是我改变Graphics对象颜色以覆盖白色圆圈的部分。当我有多个线程运行来表示我的屏幕上的多个障碍并且重绘和删除同时发生时,线程在将颜色更改为白色后被中断并使用Graphics对象绘制填充的椭圆,该颜色被另一个线程设置为黑色将delete()方法运行到最后。

如何强制程序不中断颜色变为白色和填充椭圆形图形之间的delete()方法?

1 个答案:

答案 0 :(得分:2)

声明

不推荐使用

Applet,浏览器,Oracle或社区不再支持它。试着鼓励你继续使用它们对我来说是不专业的。

我很欣赏这是一所学校&#34;任务,但也许是时候你的教练赶上了世界其他地方并开始使用一些实际上并没有引起更多问题然后解决的问题(提示JavaFX) - 恕我直言

答案...

  • 不要使用getGraphics,这不是应该如何进行自定义绘画。绘画应该在paint方法的范围内完成。有关详细信息,请查看Painting in AWT and Swing。除了解决您的直接问题,您当前的方法风险已被清除&#34;小程序重新绘制时清理。
  • 覆盖paint等顶级容器Applet是一个坏主意。除了将您锁定在一个用例中之外,它们不会被双重缓冲,这会在绘制时导致闪烁。最简单的解决方案是从JPanel开始,它是双缓冲的,可以添加到您想要使用的容器中。
  • 您不需要多个主题。线程是一种艺术形式。更多的线程并不总是意味着更多的工作完成,实际上可能会降低系统的性能。在您的情况下,您希望&#34;更新&#34;在一次通过状态,然后安排一个油漆通行证,以便操作在一个步骤中同步,你不会得到&#34;脏&#34;更新

以下示例simple使用了基于AWT的Swing。它使用JFrame而不是Applet,但这个概念很容易转移,因为核心功能基于JPanel,因此您可以将其添加到您想要的任何地方。 / p>

它使用了Swing Timer,它基本上是在常规基础上调度回调,但是在远离它可以安全地更新UI的状态(这取代了你的{{1} })。

通过使用Thread绘制paintComponent,我们可以免费获得两件事。

  1. 双缓冲,所以不再闪烁
  2. Obstacle上下文会自动为我们准备,我们不需要&#34;删除&#34;首先是对象,我们只是绘制当前状态
  3. 该示例还会在Graphics通过面板边缘时将其删除,因此当它不再可见时,您不会浪费时间尝试移动/绘制它。

    Obstacle
      

    但所有import java.awt.Color; 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 java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class Test { public static void main(String[] args) { new Test(); } public Test() { 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 { private List<Obstacle> obstacles; public TestPane() { Color[] colors = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.YELLOW}; obstacles = new ArrayList<>(10); int y = 0; for (int index = 0; index < 5; index++) { y += 55; Obstacle obstacle = new Obstacle(y, 0, colors[index]); obstacles.add(obstacle); } Timer timer = new Timer(5, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Iterator<Obstacle> it = obstacles.iterator(); while (it.hasNext()) { Obstacle ob = it.next(); if (ob.move(getSize())) { it.remove(); } } repaint(); } }); timer.start(); } @Override public Dimension getPreferredSize() { return new Dimension(400, 400); } protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); Iterator<Obstacle> it = obstacles.iterator(); while (it.hasNext()) { Obstacle ob = it.next(); ob.paint(g2d); } g2d.dispose(); } } public class Obstacle { private int x, y; private Color color; public Obstacle(int x, int y, Color color) { this.x = x; this.y = y; this.color = color; } public void paint(Graphics2D g2d) { g2d.setColor(color); g2d.fillRect(x, y, 50, 50); } public boolean move(Dimension size) { y += 1; return y > size.height; } } } 都以相同的速度移动!

    是的,那是因为你使用了一个delta。如果您希望Obstacle以不同的速率移动,则更改增量,例如......

    Obstacle