简体   繁体   English

使用地图处理 Java 中的应用程序

[英]Working with application in Java using maps

I have trouble with my Java application.我的 Java 申请有问题。 I'm writing a program that connects to public transport API and perform some operations, which includes showing map of Warsaw with bus stops.我正在编写一个连接公共交通工具 API 并执行一些操作的程序,其中包括显示华沙的 map 和公共汽车站。 I want to add an EventHandler function that allows to tap on a bus stop on the map, which will result in showing a box with some informations about this bus stop.我想添加一个事件处理程序 function,它允许点击 map 上的公交车站,这将导致显示一个框,其中包含有关该公交车站的一些信息。 How can I do such a thing?我怎么能做这样的事? My application so far: Main.java:到目前为止我的申请:Main.java:

package gui;

import api.Api;
import com.gluonhq.charm.down.ServiceFactory;
import com.gluonhq.charm.down.Services;
import com.gluonhq.charm.down.plugins.StorageService;
import com.gluonhq.maps.MapPoint;
import com.gluonhq.maps.MapView;
import com.gluonhq.maps.demo.PoiLayer;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

import java.io.File;
import java.util.*;

import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;

import javax.swing.*;

public class Main extends Application{
    private ContentType currentContent = ContentType.SCHEDULE;
    private HashMap<ContentType, Pane> contentPaneMap;
    private HBox buttonBox;
    private Stage stage;
    private Theme theme;
    private final int height = 500;
    private final int width = 800;
    private final ToggleGroup menuButtonToggle = new ToggleGroup();
    private String selectedStopId;

    @Override
    public void start(Stage primaryStage) {
        this.stage = primaryStage;
        theme = Theme.DARK;
        buttonBox = new HBox();
        buttonBox.getChildren().addAll(getMenuButtons());
        initContentPanes();
        getContentPaneAndResetStage();
        primaryStage.show();
    }

    private void getContentPaneAndResetStage(){
        Pane contentPane = contentPaneMap.get(currentContent);
        VBox rootPane = new VBox();
        rootPane.getChildren().addAll(buttonBox, contentPane);
        Scene scene = new Scene(rootPane, width, height);
        scene.getStylesheets().add(theme.cssFile);
        stage.setScene(scene);
    }

    private List<ToggleButton> getMenuButtons(){
        List<ToggleButton> buttonList = new ArrayList<>();
        for(ContentType contentType:ContentType.values()){
            ToggleButton button = new ToggleButton(contentType.buttonText);
            button.setPrefWidth((double) width/4);
            button.setOnAction(e -> {
                Main.this.currentContent = contentType;
                getContentPaneAndResetStage();
            });
            buttonList.add(button);
            button.setToggleGroup(Main.this.menuButtonToggle);
        }
        return buttonList;
    }

    private void initContentPanes(){
        contentPaneMap = new HashMap<>();
        Api.saveLocalisationToCache();
        contentPaneMap.put(ContentType.MAP, getMapPane());
        contentPaneMap.put(ContentType.SCHEDULE, getSchedulePane());
        contentPaneMap.put(ContentType.ROUTE, getRoutePane());
        contentPaneMap.put(ContentType.SETTINGS, getSettingsPane());
    }

    private Pane getSchedulePane(){
        VBox schedulePane = new VBox();
        Label stopNameLabel = new Label("Nazwa przystanku: ");
        stopNameLabel.setPadding(new Insets(5));
        TextField stopName = new TextField();
        stopName.setOnAction(e -> {
            List<String> stopId = Api.getId(stopName.getText());
            selectedStopId = null;
            schedulePane.getChildren().remove(1);
            schedulePane.getChildren().add(getContentForSchedulePane(stopId, stopName.getText()));
        });
        schedulePane.getChildren().add(new HBox(stopNameLabel, stopName));
        if (selectedStopId == null) schedulePane.getChildren().add(new Pane(new Label("Nie znaleziono przystanku")));
        else schedulePane.getChildren().add(new Label(selectedStopId));
        return schedulePane;
    }

    private Pane getContentForSchedulePane(List<String> stopId, String stopName){
        if (stopId.size() == 0) return new Pane(new Label("Nie znaleziono przystanku"));
        if (stopId.size() == 1) {
            String stop1id = stopId.get(0);
            Label stopNameLabel = new Label("Przystanek " + stopName.toUpperCase() + " (id " + stop1id + ")");
            stopNameLabel.setPadding(new Insets(5));
            VBox newContentPane = new VBox(stopNameLabel);
            ChoiceBox<String> busStopNr = new ChoiceBox<>(
                    FXCollections.observableArrayList(List.of(new String[]{"01", "02"})));
            busStopNr.setValue("01");
            ChoiceBox<String> lineChoice = new ChoiceBox<>(
                    FXCollections.observableArrayList(Api.getLines(stop1id, busStopNr.getValue())));
            Label times = new Label();
            lineChoice.setOnAction(
                    e -> times.setText(Api.getTimes(stop1id, busStopNr.getValue(), lineChoice.getValue()).toString()));
            busStopNr.setOnAction(
                    e -> lineChoice.setItems(
                            FXCollections.observableArrayList(Api.getLines(stop1id, busStopNr.getValue()))));
            newContentPane.getChildren().addAll(
                    new HBox(new Label("Nr słupka: "), busStopNr),
                    new HBox(new Label("Nr linii: "), lineChoice),
                    times);
            return newContentPane;
        }
        GridPane newButtonPane = new GridPane();
        int i = 1; int j = 0;
        for (String id:stopId) {
            Button b = new Button(id);
            b.setOnAction(event -> {
                selectedStopId = b.getText();
                contentPaneMap.get(ContentType.SCHEDULE).getChildren().remove(1);
                contentPaneMap.get(ContentType.SCHEDULE).getChildren()
                        .add(getContentForSchedulePane(Collections.singletonList(b.getText()), stopName));
            });
            ((GridPane) newButtonPane).add(b, i, j);
            i = (i+1)%4+1; j = i==1?j+1:j;
        }
        return newButtonPane;
    }

    private Pane getRoutePane(){return new VBox(new Circle(20, Color.BLUE));}

    private Pane getMapPane(){
        MapView mapView = new MapView();
        PoiLayer poiLayer = new PoiLayer();
        List<Map<String, String>> pointList = Api.getLocalization();
        for (Map<String, String> stop: pointList){
            MapPoint point = new MapPoint(Double.parseDouble(stop.get("szer_geo")), Double.parseDouble(stop.get("dlug_geo")));
            poiLayer.addPoint(point, new Circle(3, Color.RED));
        }
        mapView.setCenter(new MapPoint(52.230926, 21.006701));
        mapView.setZoom(13);
        mapView.addLayer(poiLayer);
        return new StackPane(mapView);
    }

    public void getInfo(){

    }
    private Pane getSettingsPane(){
        GridPane settingsPane = new GridPane();
        ChoiceBox<Theme> themeChoiceBox = new ChoiceBox<>(FXCollections.observableArrayList(Theme.values()));
        themeChoiceBox.setOnAction(e -> {
            Main.this.theme = themeChoiceBox.getValue();
            getContentPaneAndResetStage();
        });
        Label themeLabel = new Label("Motyw: ");
        themeLabel.setPadding(new Insets(5));
        settingsPane.add(themeLabel, 1, 1);
        settingsPane.add(themeChoiceBox, 2, 1);
        settingsPane.setHgap(10);
        settingsPane.setVgap(10);
        settingsPane.setGridLinesVisible(false);
        return settingsPane;
    }

    @Override
    public void init() {
        System.setProperty("javafx.platform", "Desktop");
        System.setProperty("http.agent", "Gluon Mobile/1.0.1");
        StorageService storageService = new StorageService() {
            @Override
            public Optional<File> getPrivateStorage() {
                return Optional.of(new File(System.getProperty("user.home")));
            }
            @Override
            public Optional<File> getPublicStorage(String s) {
                return getPrivateStorage();
            }
            @Override
            public boolean isExternalStorageWritable() {
                return getPrivateStorage().isPresent() && getPrivateStorage().get().canWrite();
            }
            @Override
            public boolean isExternalStorageReadable() {
                return getPrivateStorage().isPresent() && getPrivateStorage().get().canRead();
            }
        };
        ServiceFactory<StorageService> storageServiceServiceFactory = new ServiceFactory<>() {
            @Override
            public Class<StorageService> getServiceType() {
                return StorageService.class;
            }

            @Override
            public Optional<StorageService> getInstance() {
                return Optional.of(storageService);
            }
        };
        Services.registerServiceFactory(storageServiceServiceFactory);
    }
}

api.java: api.java:

package api;

import javafx.application.Platform;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Api {

    private static final String baseUrl = "https://api.um.warszawa.pl/api/action/";
    private static final String apikey = "95904037-5fdc-48d5-bd7f-c9f8d0b28947";
    private static final String pathToLocalisationCache = "./.cache/stop-localisation.json";

    private static HttpURLConnection getConnection(String urlString){
        URL url = null;
        HttpURLConnection connection = null;
        try {
            url = new URL(urlString);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        try {
            assert url != null;
            connection = (HttpURLConnection)url.openConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return connection;
    }
    //Współrzędne przystanków
    public static List<Map<String,String>> getLocalization() {
        File cacheFile = new File(pathToLocalisationCache);
        String data;
        if(!cacheFile.exists()){
            String url = baseUrl+"dbstore_get?id=ab75c33d-3a26-4342-b36a-6e5fef0a3ac3&apikey="+apikey;
            HttpURLConnection connection = Api.setParameters(getConnection(url));
            data = Api.readData(connection);
        } else{
            data = readLocalisationFromCache();
        }

        List<Map<String,String>> list = new ArrayList<>();
        assert data != null;
        JSONObject obj = new JSONObject(data);
        JSONArray arr = obj.getJSONArray("result");
        for(int j=0; j<arr.length();j++){
            JSONObject obj1 = arr.getJSONObject(j);
            JSONArray arr1 = obj1.getJSONArray("values");
            Map<String, String> map = new HashMap<>();
            for(int i = 0; i < arr1.length();i++){
                String value = arr1.getJSONObject(i).getString("value");
                String key = arr1.getJSONObject(i).getString("key");
                map.put(key, value);
            }
            list.add(map);
        }
        return list;
    }

    public static void saveLocalisationToCache(){
        File file = new File(pathToLocalisationCache);
        if (file.exists()) return;
        try{
            boolean fileCreated = true;
            if (!file.getParentFile().exists()) fileCreated = file.getParentFile().mkdir();
            if (!fileCreated) throw new IOException("Unable to create cache directory");
            fileCreated = file.createNewFile();
            if (!fileCreated) throw new IOException("Unable to create file");
            String url = baseUrl+"dbstore_get?id=ab75c33d-3a26-4342-b36a-6e5fef0a3ac3&apikey="+apikey;
            HttpURLConnection connection = setParameters(getConnection(url));
            InputStreamReader in = new InputStreamReader(new BufferedInputStream(connection.getInputStream()), StandardCharsets.UTF_8.newDecoder());
            OutputStreamWriter out = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(file)), StandardCharsets.UTF_8.newEncoder());
            in.transferTo(out);
            in.close(); out.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String readLocalisationFromCache(){
        try{
            BufferedReader reader = new BufferedReader(new FileReader(pathToLocalisationCache));
            StringBuilder dataSB = new StringBuilder();
            reader.lines().forEach(dataSB::append);
            reader.close();
            return dataSB.toString();
        } catch (IOException e){e.printStackTrace();}
        return null;
    }


    //id przystanku po nazwie
    public static List<String> getId(String n) {
        StringBuilder name = new StringBuilder();
        try {
            String[] testStrings = {n};
            for (String s : testStrings) {
                String encodedString = URLEncoder.encode(s, StandardCharsets.UTF_8);
                name.append(encodedString);
            }
        } catch(Exception e){e.printStackTrace();}

        String url = baseUrl+"dbtimetable_get?id=b27f4c17-5c50-4a5b-89dd-236b282bc499&name="+name+"&apikey="+apikey;

        HttpURLConnection connection = Api.setParameters(getConnection(url));
        String data = Api.readData(connection);
        assert data != null;
        JSONObject json = new JSONObject(data);
        Pattern integerPattern = Pattern.compile("-?\\d+");
        Matcher matcher = integerPattern.matcher(json.toString());
        List<String> linesList = new ArrayList<>();
        while (matcher.find()) {
            linesList.add(matcher.group());
        }
        return linesList;
    }

    // Zwraca liste linii dla konkretnego przystanku i nr slupka
    public static List<String> getLines(String idPrzystanku, String nrSlupka) {
        String url = baseUrl+"dbtimetable_get?id=88cd555f-6f31-43ca-9de4-66c479ad5942&busstopId="+
                idPrzystanku+"&busstopNr="+nrSlupka+"&apikey="+apikey;

        HttpURLConnection connection = Api.setParameters(getConnection(url));
        String data = Api.readData(connection);
        assert data != null;
        JSONObject json = new JSONObject(data);
        Pattern integerPattern = Pattern.compile("-?\\d+");
        Matcher matcher = integerPattern.matcher(json.toString());
        List<String> linesList = new ArrayList<>();
        while (matcher.find()) {
            linesList.add(matcher.group());
        }
        return linesList;
    }

    //Zwraca listę czas dla danego przystanku i linii
    public static List<String> getTimes(String idPrzystanku, String nrSlupka, String line) {
        String url = baseUrl+"dbtimetable_get?id=e923fa0e-d96c-43f9-ae6e-60518c9f3238&busstopId="+
                idPrzystanku+"&busstopNr="+nrSlupka+"&line="+line+"&apikey="+apikey;

        HttpURLConnection connection = Api.setParameters(getConnection(url));
        String data = Api.readData(connection);

        List<String> times = new ArrayList<>();
        assert data != null;
        JSONObject obj = new JSONObject(data);
        JSONArray arr = obj.getJSONArray("result");
        for(int j=0; j<arr.length();j++){
            JSONObject obj1 = arr.getJSONObject(j);
            JSONArray arr1 = obj1.getJSONArray("values");
            JSONObject obj2 = arr1.getJSONObject(5);
            times.add(obj2.getString("value"));
        }
        return times;
    }

    //Odczytuje dane
    public static String readData(HttpURLConnection connection) {
        InputStream inStream;
        try {
            inStream = new BufferedInputStream(connection.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        Scanner in = new Scanner(inStream, StandardCharsets.UTF_8);
        StringBuilder sb = new StringBuilder();
        while (in.hasNext()) {
            sb.append(in.next());
        }
        return sb.toString();
    }

    //Ustala parametry połączenia
    public static HttpURLConnection setParameters(HttpURLConnection
                                                          connection) {
        try {
            connection.setRequestMethod("GET");
            connection.setDoInput(true);
        } catch (ProtocolException e) {
            e.printStackTrace();
        }
        connection.setRequestProperty("Authorization", "Token " + apikey);
        try {
            if (connection.getResponseCode() != 200) {
                System.out.println("Response code: "
                        + connection.getResponseCode() + " " + connection.getResponseMessage());
                Platform.exit(); // ze względu na javafx
                System.exit(0);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

I have no idea how to do it and I will be very grateful if someone will help me.我不知道该怎么做,如果有人能帮助我,我将不胜感激。

Based on my work experience on map libraries with JavaFX, I can share an approach you can take here.根据我在 map 库和 JavaFX 上的工作经验,我可以在这里分享一种您可以采用的方法。 You can simply add a Mouse click event handler on the MapView and in that event you can catch the coordinates/ Point where the user clicks on the screen.您可以简单地在MapView上添加一个鼠标单击事件处理程序,在这种情况下,您可以捕获用户在屏幕上单击的坐标/ Point Then you can compare that point clicked by the user with one of the location Map points you want your user to click and see if it matches (by checking a distance between the user click position and the map coordinate of the bus stop).然后,您可以将用户点击的那个点与您希望用户点击的位置 Map 点之一进行比较,看看它是否匹配(通过检查用户点击 position 和公交车站坐标 map 之间的距离)。 I have applied this approach in a different map library but similar can be applied here with some tweaks and adjustments.我在不同的 map 库中应用了这种方法,但类似的方法可以通过一些调整和调整应用到这里。

List<Map<String, String>> pointList = Api.getLocalization();

        mapView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {

                Point2D clickedMapCoordinates = mapView.screenToLocal(new Point2D(mouseEvent.getX(), mouseEvent.getY()));

                for (Map<String, String> stop: pointList){
                    MapPoint stopPoint = new MapPoint(Double.parseDouble(stop.get("szer_geo")), Double.parseDouble(stop.get("dlug_geo")));

                    Point2D mapStopPoint = new Point2D(stopPoint.getLongitude(), stopPoint.getLatitude());

                    // if user clicked on map near the position(lat,lng) of a stop
                    // then trigger the logic, you can change the distance threshold value according to your need
                    if(mapStopPoint.distance(clickedMapCoordinates) < 0.0001)
                    {
                        // perform your logic here about the stop point point...
                    }
                }
            }
        });

Another approach which I suppose you can take is put a click event handler on the Circle object for the bus stop point and then check if the user's clicked circle matches the coordinates of a bus stop point.我认为您可以采用的另一种方法是在公交车站点的Circle object 上放置一个点击事件处理程序,然后检查用户点击的圆圈是否与公交车站点的坐标相匹配。

Circle circle = new Circle(3, Color.RED);
        circle.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                if(mouseEvent.getSource() instanceof Circle)
                {
                    Circle clickedCircle = (Circle) mouseEvent.getSource();
                    Point2D clickedPoint = mapView.screenToLocal(clickedCircle.getCenterX(), clickedCircle.getCenterY())

                    for (Map<String, String> stop: pointList){
                        MapPoint point = new MapPoint(Double.parseDouble(stop.get("szer_geo")), Double.parseDouble(stop.get("dlug_geo")));

                        if(clickedPoint.getX() == point.getLongitude() && clickedPoint.getY() == point.getLatitude())
                        {
                            // this is the clicked map point (bus stop point)
                            // perform your logic here
                        }
                    }
                }
            }
        });

If the second approach doesn't work, try debugging and checking the clicked point and bus stop point coordinates values and adjust them.如果第二种方法不行,请尝试调试检查点击点和公交站台坐标值并进行调整。 Hope this helps you in some way.希望这能以某种方式帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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