简体   繁体   中英

Painting points on a MapLayer using GluonHQ Maps with JavaFX does not work

I am using GluonHQ Maps 1.0.3 in JavaFX and I have a problem painting nodes on the map.

I have a class GridMapController which has a MapView called gridMap . I also have a class GridPaintLayer that extends the MapLayer and where all paintings are done. The GridPaintLayer is added to the GridMapController 's gridMap with the method gridMap.addLayer(gridPaintLayer) . This class ( GridPaintLayer ) has a method addNode(NodeInputModel) to which I pass a node (that contains lat/lon values) that shall be painted. The mentioned gridMap ( MapView ) can be right-clicked, a popup menu opens where I can choose "Create Node". This calls a method createNodeItemClicked() which is implemented in the GridPaintLayer (see below). When I click the "Create Node" menu item, everything works fine and a point appears on the map.

In another part of the programm I have an observable object that notifies its observers whenever a node is added. The notification message is handled in the GridMapController which then calls the addNode() method from the GridPaintLayer . But now, when I want the GridPaintLayer's baseMap to calculate the the points position on the scene, the method baseMap.getMapPoint(double lat, double lon) returns null because the baseMap's scene is null . So the node cannot be painted. This happens ie when I want to create a node at another part of the application. The observable notifies the GridMapController (among others) correctly but then the problem appears as described above.

The methods below are both implemented in the GridPaintLayer class.

public void addNode(NodeInputModel nodeInputModel) {
    Circle circle = new Circle(7, Color.RED);
    circle.setCursor(Cursor.HAND);
    circle.setVisible(true);

    paintedNodes.put(nodeInputModel, circle);

    Point2D mapPoint = baseMap.getMapPoint(nodeInputModel.getLat(), nodeInputModel.getLon());
    if(mapPoint != null) {
        circle.setTranslateX(mapPoint.getX());
        circle.setTranslateY(mapPoint.getY());
    } else {
        System.out.println("Could not calculate node position, baseMap scene = null: " + (baseMap.getScene() == null));
    }

    AtomicReference<Double> orgSceneX = new AtomicReference<>(0d);
    AtomicReference<Double> orgSceneY = new AtomicReference<>(0d);

    circle.setOnMousePressed(mousePressedEvent -> {...});

    circle.setonMouseClicked(mouseEvent -> {...});

    this.getChildren().add(circle);
    this.markDirty();
}

public void createNodeItemClicked(MouseEvent mouseEvent) {
    // Convert mouseEvent position to geo position
    MapPoint mapPoint = baseMap.getMapPosition(mouseEvent.getX(), mouseEvent.getY());
    LatLon latLon = new LatLon(mapPoint.getLatitude(), mapPoint.getLongitude());
    Point geoPosition = Utils.latlonToPoint(latLon);

    // Create NodeInputModel
    NodeInputModel nodeInputModel = new NodeInputModel();
    nodeInputModel.setGeoPosition(geoPosition);
    // TODO: set the other parameters

    // Add node to Map
    addNode(nodeInputModel);

    // Send update message to GridModel
    UpdateMessage updateMessage =
                    new UpdateMessage(null, Arrays.asList(nodeInputModel), UpdateMessage.UpdateType.ADD);
    gridMapController.sendUpdateMessage(updateMessage);
}

I have tried several things to "reactivate" the scene but nothing worked. Is there a way to do that properly? I hope I have explained everything clearly. If not, please feel free to ask.

Edit: I am using multiple FXML files. The root FXML (MainView.fxml):

<VBox   xmlns="http://javafx.com/javafx/8.0.172-ea"
        xmlns:fx="http://javafx.com/fxml/1"
        fx:id="main"
        fx:controller="edu.ie3.controller.main.MainController">

    <fx:include fx:id="io" source="IoView.fxml"/>

    <fx:include fx:id="tool" source="ToolView.fxml"/>

    <HBox prefHeight="${main.height}">
        <!-- vertical button bar for grid info -->
        <ButtonBar fx:id="leftButtonBar" rotate="-90">
            <buttons>
                <Button fx:id="gridInfoButton" text="Grid Info"/>
            </buttons>
        </ButtonBar>

        <SplitPane fx:id="splitPane" prefWidth="${main.width}">
            <fx:include fx:id="gridTab" source="GridTabView.fxml"/>
        </SplitPane>

    </HBox>

    <fx:define>
        <fx:include fx:id="gridInfo" source="GridInfoView.fxml"/>
        <fx:include fx:id="gridMap" source="GridMapView.fxml"/>
        <fx:include fx:id="gridSchema" source="GridSchemaView.fxml"/>
    </fx:define>

</VBox>

The Splitpane which contains the GridMapView:

<TabPane
        xmlns="http://javafx.com/javafx/8.0.172-ea"
        xmlns:fx="http://javafx.com/fxml/1"
        tabClosingPolicy="UNAVAILABLE"
        fx:id="gridTabPane"
        fx:controller="edu.ie3.controller.gridTab.GridTabController">

    <Tab fx:id="gridMapTab" text="Map View">
        <fx:include fx:id="gridMapLayer" source="GridMapView.fxml"/>
    </Tab>

    <Tab fx:id="gridSchemaTab" text="Schema View">
        <fx:include fx:id="gridSchema" source="GridSchemaView.fxml"/>
    </Tab>

</TabPane>

The GridMapView.fxml looks like this:

<?xml version="1.0" encoding="UTF-8"?>

<?import com.gluonhq.maps.MapView?>
<MapView xmlns="http://javafx.com/javafx/8.0.172-ea"
     xmlns:fx="http://javafx.com/fxml/1"
     fx:id="gridMap"
     fx:controller="edu.ie3.controller.gridTab.gridMap.GridMapController">
</MapView>

I have already tried commenting some statements out to avoid double including the GridMapView but nothing worked.

I solved it. The problem was that I included the GridMapController once in the MainController and once in the GridTabController. I removed the fx:include from the MainController and now the GridMapController only initializes once. Nevertheless thank you very much, José Pereda, you brought me on the right way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM