How can I ensure correct drawing order in an Overl

2019-07-04 16:41发布

问题:

I am using a JPanel with an OverlayLayout to draw two unrelated components on top of each other. Specifically, I have a transparent component which contains my own line drawings, and beneath that, I am using a JMapViewer component, which displays OpenStreetMap tiles. This works.

Except when the JMapViewer loads tiles asynchronously. In that case, it calls repaint() on itself when the loading is finished, and it draws itself over my line layer. My line layer cannot know this, since it cannot know when the JMapViewer chooses to repaint itself.

Now I would have expected the JPanel to repaint my line layer when the map layer repaints, since it knows the correct drawing order and knows that my line layer has to be repainted. But it doesn't do this.

How would you solve this?

回答1:

JMapViewer implements TileLoaderListener and simply calls repaint() when loading is finished. You should be able to update the map and then forward the event to your layer, as suggested below.

MyViewer map = new MyViewer();
...
private class MyViewer extends JMapViewer {

    @Override
    public void tileLoadingFinished(Tile tile, boolean success) {
        super.tileLoadingFinished(tile, success);
        lineLayer.repaint(); 
    }
}


回答2:

it calls repaint() on itself when the loading is finished,

Call repaint() on the parent panel instead.



回答3:

This depends on how the JMapViewer repaints itself. If it just updates its content, the parent(s) might not even notice that something has changed.



回答4:

I don't know if this is the best approach, but it's the only one I can think of. You could replace the RepaintManager for the JMapComponent with a custom one that also manages repaints of your overlayed component. That way, you can guarantee that your overlayed component always gets repainted last.

...do this from the AWT event thread via SwingUtilities

RepaintManager myManager = new RepaintManager() {
   public void  addDirtyRegion(JComponent c, int x, int y, int w, int h) {
....implemnt code here to guarentee your top level component gets repainted whenever 'c' is the JMapComponent
   }
}

RepaintManager.setCurrentManager(myManager);