[英]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.