1

我正在模拟在连接节点图上行走的人。为了直观地显示它,我使用了画布对象。我首先通过它的节点和它们之间的链接来渲染图形,然后我开始绘制由在图形中移动的小方块表示的人。

我的问题是,在我绘制地图(或图表)后,人的动画会删除标签,有时还会删除图表的线条。我知道这是因为我在包含地图的同一画布上渲染了人的运动(并且因为clearRect()方法调用)。

我怎样才能避免清除图表?,起初我看着JLayeredPane但画布重叠并且在最上面的画布上没有透明度(没有透明的人)。我想到的第二个选项是在绘制人之前复制该区域,然后在人移动时恢复该区域,但我不知道如何实现这一点,所以我没有使用过swingawt没有太多使用过的指导,因此不胜感激我认为这可能是一个普遍的问题。

我附上了一张图片来显示我的问题和每个人的渲染代码

public class Person extends Thread {

    public Person(String name, Spot location, World world, Graphics g) {
    this.name= name;
    this.location= location;
    this.world= world;
    this.g= g;
}

private void move() {
    Set<Link> links= world.getLinksFrom(location.getId());  
Link route= CollectionUtil.getRandomElement(links);  
Spot destination= route.getOriginX() == location.getX() &&   
    route.getOriginY() == location.getY() ?  
    route.getTheTarget(): route.getTheOrigin();  

try {
    double deltaX= (destination.getX() - location.getX()) / route.distance();
    double deltaY= (destination.getY() - location.getY()) / route.distance();
    double w2= (PERSON_WIDTH / 2);

    for(double i=location.getX(), j=location.getY(), d= route.distance(); 
    d > 5;
    i+=deltaX, j+= deltaY, 
    d=Point2D.distance(i, j, destination.getX(), destination.getY())) {
            g.clearRect((int)(i - w2 - deltaX), (int)(j - w2 - deltaY), 
        PERSON_WIDTH, PERSON_WIDTH);
        g.drawRect((int)(i-w2), (int)(j-w2), 
        PERSON_WIDTH-1, PERSON_WIDTH-1);
        Thread.sleep(50);
    }

    this.location= destination;

    // Stay ath the new location for a while
    Thread.sleep(new Random(System.currentTimeMillis()).nextInt(Person.MAX_SPOT_MILLIS));
    } catch(InterruptedException e) {
        throw new RuntimeException(e);
    }

@Override
public void run() {
    while(!isInterrupted()) {
        this.move();            
    }
}
}

我的渲染问题

4

3 回答 3

1
  1. Unless you create it yourself, you should not be maintaining a reference to the Graphics context. The graphics context can be changed between repaints and repaints will override anything painted to it in between. You should overriding the paintComponet method of a custom component (like JPanel) and painting the current state of the component on each invocation
  2. It sounds like your are using java.awt.Canvas, you should avoid AWT and use Swing instead. It's a more up to date framework and is double buffered by default. You should avoid mixing AWT and Swing components as they tend not to play nice together
  3. Swing is a single threaded environment, meaning that you should only interact with the UI from within the context of the Event Dispatching Thread? Check out Concurrency in Swing for more details.
  4. There are 3 ways to do animation Swing. You can use a Thread or a javax.swing.Timer or one of the animation frameworks.

Using Threads is more complex and makes you responsible for ensuring that updates are correctly resynced by to the client. This is useful for complex animation jobs, where the time between calculating the state on each cycle my vary.

javax.swing.Timer is simpler, as it's callback is executed within the context of the EDT at regular intervals. It's great for simple animations where the time it takes to update the state are short and/or reasonable constant so that they won't have the potential of causing staggering frames

于 2013-05-27T09:12:20.270 回答
1

两种最常见的解决方案是:

  1. 每次都画图。使用双缓冲以避免闪烁。除非您的图表有很多节点并且您的计算机速度很慢,否则这应该可以正常工作。

  2. 将图形渲染成图像。在开始绘制人物之前,先绘制一次图像。这将清除整个画布。

于 2013-05-27T08:38:02.830 回答
0

如果您想尝试拥有两个画布,那么我想我可能有一个解决方案。

创建你的第一个画布来绘制你的图表,并在上面创建一个画布来吸引你的人。

您可以将顶部画布的背景颜色设置为透明颜色,然后也可以使用相同的透明颜色清除画布。

例如:

g.setBackground(new Color(0,0,0,0));
g.clearRect(0, 0, width, height);

将清除顶部画布,留下完全透明的颜色

canvas.setBackground(new Color(0,0,0,0);

将使画布组件透明。这只需要在创建画布时调用一次。

现在,在您使用 0 alpha 颜色清除顶部画布后,顶部画布将完全透明,只有您在顶部画布上绘制的内容才会遮挡底部画布。

希望这可以帮助

于 2013-05-27T08:48:04.233 回答