1

好的,所以我有两个 JFrame,每个 JFrame 内部都有不同的 JPanel 实现。当我调用repaint()JPanel 时,在一个 JPanel 上绘制的内容也会在另一个 JPanel 上绘制。

我知道我可以通过调用类似的东西来解决这个问题g.clearRect(),但是每次都需要重新绘制太多组件。

知道为什么会这样吗?

//This makes the two JFrames and JPanels, sets everything up

public void makeSpaceSimulation() {
    int dimen = 10000;
    int scale = 20;
    int numOfClusters = 30;
    int planPerCluster = 2000;
    SpaceShip s = new SpaceShip(dimen, scale);

    QuadTree t = new QuadTree(dimen, 20);
    new PlanetCreationTest(t, dimen, scale, numOfClusters, planPerCluster);

    makeMap(dimen, scale, s, t);
    makePOV(s, t, scale, dimen);
}

public void makeMap(int dimen, int scale, SpaceShip s, QuadTree t) {

    final JFrame f = new JFrame();
    f.setSize(dimen / scale, dimen / scale);
    f.setLocation(0, 0);
    f.setTitle("Map Panel");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    mapP = new MapPanel(scale, s, dimen);
    mapP.setLayout(new BorderLayout());
    mapP.addTree(t);

    f.add(mapP);
    f.setVisible(true);
    Insets i = f.getInsets();
    f.setSize(dimen / scale + (i.left + i.right) + 2, dimen / scale
            + (i.top + i.bottom) + 2);

    Thread th = new Thread() {
        public void run() {
            while (true) {
                mapP.repaint();
            }

        }
    };
    th.start();

}

public void makePOV(final SpaceShip s, QuadTree t, int scale, int dimen) {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    JFrame f = new JFrame();
    f.setSize(500, 500);
    f.setLocation(screenSize.width - 500, 0);
    f.setTitle("POV Panel");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    povP = new POVPanel(s, scale, dimen);
    povP.setLayout(new BorderLayout());
    povP.addTree(t);
    povP.setFocusable(true);

    povP.addKeyListener(new KeyListener() {

        @Override
        public void keyPressed(KeyEvent arg0) {
            final int i = arg0.getKeyCode();
            Thread th = new Thread() {
                public void run() {
                    if (i == 39) {
                        s.moveRight();
                    } else if (i == 37) {
                        s.moveLeft();
                    } else if (i == 40) {
                        s.moveDown();
                    } else if (i == 38) {
                        s.moveUp();
                    }
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }
            };
            th.start();
        }

        @Override
        public void keyReleased(KeyEvent arg0) {

        }

        @Override
        public void keyTyped(KeyEvent arg0) {

        }

    });

    f.add(povP);
    f.setVisible(true);
    Insets i = f.getInsets();
    f.setSize(dimen / 20 + (i.left + i.right) + 2, dimen / 20
            + (i.top + i.bottom) + 2);

    Thread th = new Thread() {
        public void run() {
            while (true) {
                povP.repaint();
            }

        }
    };
    th.start();

}

//here's the MapPanel

public class MapPanel extends JPanel {

private QuadTree q;
private int scale;
private int dimen;
private SpaceShip s;
private boolean firstDraw;

public MapPanel(int scale, SpaceShip s, int dimen) {
    this.dimen = dimen;
    q = new QuadTree(0, 0);
    this.scale = scale;
    this.s = s;
    firstDraw = true;
}

public void addTree(QuadTree q) {
    this.q = q;

}

public void paintComponent(Graphics g) {
    if (firstDraw) {
        q.draw(g, scale, new Point(0, 0));
        s.drawScaledGeometry(g);
        System.out.println("Totally drew that");
        firstDraw = false;
    } else {
        g.clearRect(s.viewDistance.x/scale, s.viewDistance.y/scale,
                s.viewDistance.width/scale, s.viewDistance.height/scale);
        q.quadDraw(g, scale, s.viewDistance, new Point(0, 0));
        s.drawScaledGeometry(g);
    }
}

}

//and this is the POVPanel 

public POVPanel(SpaceShip s, int scale, int dimen) {
    super();
    this.s = s;
    // this.scale = scale;
    this.dimen = dimen;
}

public void addTree(QuadTree q) {
    this.q = q;
}

public void paintComponent(Graphics g) {
    g.clearRect(0, 0, dimen / 20, dimen / 20);
    q.quadDraw(g, 1, s.viewDistance, s.getMoved());
    s.drawGeometry(g);
}
4

1 回答 1

2

这是(一个)你的问题......

public void paintComponent(Graphics g) {
    if (firstDraw) {
        q.draw(g, scale, new Point(0, 0));
        s.drawScaledGeometry(g);
        System.out.println("Totally drew that");
        firstDraw = false;
    } else {
        g.clearRect(s.viewDistance.x/scale, s.viewDistance.y/scale,
            s.viewDistance.width/scale, s.viewDistance.height/scale);
        q.quadDraw(g, scale, s.viewDistance, new Point(0, 0));
        s.drawScaledGeometry(g);
    }
}

上下文在绘制周期中共享,这Graphics意味着当您获得它时,您将获得用于绘制屏幕上所有其他组件的相同上下文。

您必须调用super.paintComponent(g),它将负责为该组件准备图形上下文以开始绘制。

更新#1

再次...

public void paintComponent(Graphics g) {
    super.paintComponent(g); // <-- Call me instead...
    //g.clearRect(0, 0, dimen / 20, dimen / 20);
    q.quadDraw(g, 1, s.viewDistance, s.getMoved());
    s.drawGeometry(g);
}

更新#2

我也对此表示严重关切

while (true) {
    mapP.repaint();
}

这可能会严重影响您的应用程序的性能。你不控制油漆周期,这是重绘经理的责任。重绘管理器将决定何时需要重绘。像这样重复调用repaint实际上可能会导致重绘管理器延迟实际调度绘制周期。

更好地使用 a javax.swing.Timer,它更简单,更安全......

Timer timer = new Timer(25, new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        mapP.repaint();
    }
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();

你可能会发现通读

有帮助

更新#3

避免KeyListener,它只会让你哭泣。相反,使用键绑定 API

于 2012-12-13T05:04:48.020 回答