【问题标题】:JavaFX : Consuming REST service and displaying the data in front-endJavaFX:使用 REST 服务并在前端显示数据
【发布时间】:2015-05-14 08:50:31
【问题描述】:

我正在开发一个 JavaFX(在带有 SceneBuilder 的 JDK8 上)项目,该项目应该与基于 Spring-MVC 的服务器连接,我想从服务器访问一些对象并显示它。我已经对 Spring 服务器进行了编程,以便根据请求返回所需的对象,但是我对 UI 编程和 JavaFX 的不熟悉使它有点困难。

在 FXML 文件中,我已经添加了一个网格窗格,我想在那里显示对象。我将不胜感激你们的任何帮助以开始。我只有基本代码,但我将其粘贴在下面:

Canvas.fxml:

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>

<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
  <columnConstraints>
    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
  </columnConstraints>
  <rowConstraints>
    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
  </rowConstraints>
</GridPane>

CanvasModel 类:

public class Canvas {

    private int canvasid;

    private final StringProperty canvasName;

    private final StringProperty canvasTitle;

    private final StringProperty canvasImage;

    private byte[] canvasImageInBytes;


    public Canvas(String canvasName, String canvasTitle, String canvasImage){
        this.canvasName = new SimpleStringProperty(canvasName);
        this.canvasTitle = new SimpleStringProperty(canvasTitle);
        this.canvasImage = new SimpleStringProperty(canvasImage);
    }
//Getters and setters ommitted
}

主类:

public class Main extends Application {

    private Stage primaryStage;

    @Override
    public void start(Stage primaryStage) throws Exception{
       Parent root = FXMLLoader.load(getClass().getResource("../View/mainui.fxml"));

primaryStage.setTitle("CheckAPP");
       primaryStage.setScene(new Scene(root, 300, 600));
        primaryStage.setFullScreen(false);
        primaryStage.setMaximized(false);

        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }

    public Stage getPrimaryStage() {
        return this.primaryStage;
    }

}

现在向下面发出请求:

http://localhost:8080/canvaslist

它将返回一个我想在 GridPane 中显示的 java.util.List。图片为字符串格式。我知道这不是一个常规问题,就像这不起作用一样,但我正试图围绕我的 UI 编程进行思考,但我不知道还能去哪里。非常感谢您的帮助。

【问题讨论】:

  • 所以您的问题是:如何在 GridPane 中显示列表?列表来自哪里并不重要。
  • @Tichodroma:是的。没错,名字、标题和图片就是一个字符串。
  • @Tichodroma : 你能帮我对付那个人吗?

标签: java spring javafx javafx-2 javafx-8


【解决方案1】:

只需加上我的几分钱来帮助你。

  1. 使用background thread 从服务中获取数据,因为可能需要一些时间才能获得响应。在 JavaFX 应用程序线程上执行它可能会导致不良的用户体验。在这种情况下,Task 将为您提供帮助。
  2. 收到回复后,从中构造一个必要的object / collection of object,您将使用它来更新场景图上的元素。
  3. 由于JavaFX Application Thread 是您可以访问live scene graph 元素的唯一线程,因此您不能直接在后台线程中使用它们(使用它们将导致IllegalStateException)。您可以使用Platform.runLater 或调用task 的方法来更新JavaFX 场景图上的数据,这些方法保证会更新FX 应用程序线程上的状态,例如updateProgress(...)updateMessage(...)getValue(...) 等.
  4. 使用您在Step-2 中构建的object / collection of object 创建(或更新)FX 场景图元素。
  5. 如果您有一个接受ObservableList 作为其内容的控件(如TableView 或ListView),您只需绑定 内容和Task 的属性之一,即可更新它们会在执行期间/之后自动执行,具体取决于它们的使用情况。
  6. 但在你的情况下,既然你有GridPane,所以我们可能需要更进一步,编写逻辑来创建控件并将它们添加到GridPane

示例

我创建了一个使用服务的示例,解析 JSON 数据并从中创建一个GridPane。 JSON 中有 list of few people on StackOverflow 和他们的名字、他们的喜好(根据我)和 SO 上的个人资料图片。

它使用后台任务从服务加载 JSON 数据,使用任务的 setOnSucceeded(...) 处理程序将其传递给创建 GridPanecreateGridPane(onservableList)

GridPane 的其中一列包含相应人员的个人资料图片。由于下载这些图片可能需要一些时间,因此我为每个用户生成了 multiple threadsload the image

您可以找到source code here

它使用GSON 作为库将JSON 转换为POJO 类。

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ConsumeJSON extends Application {

    private ObservableList<PeopleOnSO> listOfPeople;
    private static final String JSON_URL = "https://api.myjson.com/bins/3jwmh";
    private static final String IMAGE_URL = "http://www.fontspring.com/presentation_20150512/images/ajax_loader_blue_512.gif";
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    private Image loadImage;

    @Override
    public void start(Stage stage) throws Exception {

        loadImage = new Image(IMAGE_URL);
        VBox root = new VBox();
        root.setAlignment(Pos.TOP_CENTER);
        root.setPadding(new Insets(20));
        root.setSpacing(20);

        Button button = new Button("Fill GridPane");

        root.getChildren().addAll(button);


        button.setOnAction(e -> {
            // Display loading image
            ImageView loading = new ImageView(loadImage);
            loading.setFitWidth(60);
            loading.setFitHeight(60);
            root.getChildren().add(loading);
            executorService.submit(fetchList);
        });


        fetchList.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                listOfPeople = FXCollections.observableArrayList(fetchList.getValue());
                GridPane gridPane = createGridPane(listOfPeople);
                //Remove Loading Image and add GridPane
                root.getChildren().remove(1);
                VBox.setVgrow(gridPane, Priority.ALWAYS);
                root.getChildren().add(gridPane);
                stage.sizeToScene();
            }
        });

        ScrollPane scrollPane = new ScrollPane(root);
        Scene scene = new Scene(scrollPane, 600, 500);
        stage.setScene(scene);
        stage.setTitle("Load Data from JSON");
        stage.show();

        stage.setOnCloseRequest(e -> {
            executorService.shutdown();
        });
    }

    public GridPane createGridPane(ObservableList<PeopleOnSO> listOfPeople){
        GridPane gridPane = new GridPane();
        gridPane.setAlignment(Pos.CENTER);
        gridPane.setGridLinesVisible(true);
        gridPane.setPadding(new Insets(20));
        gridPane.setMinHeight(500);
        gridPane.setMaxWidth(500);

        //Create headings
        Label nameHeading = new Label("Name");
        nameHeading.setStyle("-fx-font-weight: bold");
        Label likeHeading = new Label("Likes");
        likeHeading.setStyle("-fx-font-weight: bold");
        Label imageHeading = new Label("Image");
        imageHeading.setStyle("-fx-font-weight: bold");

        gridPane.add(nameHeading, 0, 0);
        gridPane.add(likeHeading, 1, 0);
        gridPane.add(imageHeading, 2, 0);

        // Aligning at center
        alignElements(nameHeading, likeHeading, imageHeading);

        // Setting Constraints
        for (int i = 0; i < 3; i++) {
            ColumnConstraints column = new ColumnConstraints(150);
            // column.setPercentWidth(80);
            gridPane.getColumnConstraints().add(column);
        }

        for (int i = 0; i < listOfPeople.size(); i++) {

            PeopleOnSO people = listOfPeople.get(i);
            Label nameLabel = new Label(people.getName());
            Label likeLabel = new Label(people.getLike());
            ImageView imageView = new ImageView(loadImage);
            imageView.setFitHeight(60);
            imageView.setFitWidth(60);

            //Thread for loading images later
            FetchImage fetchImage = new FetchImage(people.getImageUrl());
            fetchImage.setOnSucceeded(worker -> {
                imageView.setImage((Image) fetchImage.getValue());
            });

            executorService.submit(fetchImage);

            // Adding to GridPane and necessary configuration
            gridPane.add(nameLabel, 0, i + 1);
            gridPane.add(likeLabel, 1, i + 1);
            gridPane.add(imageView, 2, i + 1);

            //Aligning at center
            alignElements(nameLabel, likeLabel, imageView);

            gridPane.getRowConstraints().add(new RowConstraints(80));
        }
        return gridPane;
    }

    /**
     * Align elements at the center
     * @param nodes
     */
    private void alignElements(Node ... nodes ) {
        for(Node node : nodes) {
            GridPane.setHalignment(node, HPos.CENTER);
            GridPane.setValignment(node, VPos.CENTER);
        }
    }

    /**
     * Task to fetch details from JSONURL
     * @param <V>
     */
    private Task<List<PeopleOnSO>> fetchList = new Task() {
        @Override
        protected List<PeopleOnSO> call() throws Exception {
            List<PeopleOnSO> list = null;
            try {
                Gson gson = new Gson();
                list = new Gson().fromJson(readUrl(JSON_URL), new TypeToken<List<PeopleOnSO>>() {
                }.getType());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return list;
        }
    };

    /**
     * Task to fetch images for individual ImageViews
     * @param <V>
     */
    private class FetchImage<V> extends Task<Image> {

        private String imageUrl;

        public FetchImage(String imageUrl) {
            this.imageUrl = imageUrl;
        }

        @Override
        protected Image call() throws Exception {
            Image image = new Image(imageUrl);
            return image;
        }

    }

    /**
     * Read the URL and return the json data
     * @param urlString
     * @return
     * @throws Exception
     */
    private static String readUrl(String urlString) throws Exception {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlString);
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuffer buffer = new StringBuffer();
            int read;
            char[] chars = new char[1024];
            while ((read = reader.read(chars)) != -1)
                buffer.append(chars, 0, read);

            return buffer.toString();
        } finally {
            if (reader != null)
                reader.close();
        }
    }

    private class PeopleOnSO {

        private final String name;
        private final String like;
        private final String imageUrl;

        public PeopleOnSO(String name, String like, String imageUrl){
            this.name = new String(name);
            this.like = new String(like);
            this.imageUrl = new String(imageUrl);
        }

        public String getName() {
            return name;
        }

        public String getLike() {
            return like;
        }

        public String getImageUrl() {
            return imageUrl;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

【讨论】:

  • 如果你把这叫做加一分钱,那你有低估我的朋友的天赋。非常感谢。这有助于我快速开始。
  • 我肯定会集成这段代码,但我正在尝试一些东西,但失败了:stackoverflow.com/questions/30237574/…。你能看看吗。
  • 我没用过JsonParser,但是你可以直接将json转成pojo,使用Jackson mapper或者GSON。
  • 嗨,你能在JavaFX上检查这个问题吗:stackoverflow.com/questions/31157187/…
猜你喜欢
  • 2015-03-16
  • 1970-01-01
  • 2018-11-26
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 2018-05-29
  • 2012-08-08
  • 2016-06-22
相关资源
最近更新 更多