java JavaFX - 处理窗口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27889614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 12:35:04  来源:igfitidea点击:

JavaFX - Dispose of window

javajavafxdispose

提问by JamEngulfer

I've got a window in JavaFX that I need to 'clean' I.E: Reset the values of all of the fields and set it back to how it was when it was initialised. I figured I could do something like window.dispose(), but it turns out nothing like that appears to exist.

我在 JavaFX 中有一个窗口,我需要“清理”IE:重置所有字段的值并将其设置回初始化时的状态。我想我可以做类似的事情window.dispose(),但事实证明似乎不存在这样的事情。

This seems like a massive oversight in the window engine as I'm going to be opening multiple windows that I don't want to persist. If I do stage.close()it just hides the window without releasing the memory, potentially leading to memory leaks.

这似乎是窗口引擎中的一个巨大疏忽,因为我将要打开多个不想保留的窗口。如果我这样做stage.close()只是隐藏窗口而不释放内存,可能会导致内存泄漏。

回答by James_D

When you call close(), (or, equivalently, hide()) on a window, the FX toolkit will release any references it holds to that window. Consequently, as long as you do not retain references to the window, once close()has been called it will be eligible for garbage collection. It behaves like any other Java object with respect to garbage collection - once garbage collected, resources associated with the window are released.

当您在窗口上调用close(), (或等效地,hide())时,FX 工具包将释放它持有的对该窗口的所有引用。因此,只要您不保留对窗口的引用,一旦close()被调用,它将有资格进行垃圾收集。在垃圾回收方面,它的行为与任何其他 Java 对象一样——一旦垃圾回收,与窗口关联的资源就会被释放。

Here's a demo that opens a new window every second, closing the previous window when it does so. The window displays an image in a label, so it consumes a reasonable chunk of memory. The primary stage displays memory statistics (also updating every second). This behaves exactly as you would expect, with the memory gradually increasing until the garbage collector kicks in, at which point the memory usage drops back. (On my system, it cycles between ~7MB and ~65MB; your mileage may vary depending on OS, JDK version, and system resources.) You can insert a call to System.gc();at the end of the onSucceededhandler (for demo purposes only; I do not recommend doing this in real code) if you want to see more clearly that garbage collection releases all the resources.

这是一个演示,每秒打开一个新窗口,并在打开时关闭上一个窗口。该窗口在标签中显示图像,因此它消耗了合理的内存块。初级阶段显示内存统计信息(也每秒更新一次)。这与您预期的完全一样,内存逐渐增加,直到垃圾收集器启动,此时内存使用量回落。(在我的系统上,它在 ~7MB 和 ~65MB 之间循环;您的里程可能因操作系统、JDK 版本和系统资源而异。)您可以System.gc();onSucceeded处理程序的末尾插入一个调用(仅用于演示目的;我愿意不建议在实际代码中这样做)如果你想更清楚地看到垃圾收集释放了所有资源。

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.LongProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;

public class ConstantlyOpenWindows extends Application {

    @Override
    public void start(Stage primaryStage) {

        ScheduledService<?> service = periodicallyShowNewWindow();

        Pane root = createMemoryMonitor();
        primaryStage.setScene(new Scene(root, 800, 600));

        primaryStage.show();

        service.start();

    }


    private ScheduledService<Integer> periodicallyShowNewWindow() {

        Screen screen = Screen.getPrimary();
        double maxX = screen.getBounds().getMaxX();

        AtomicInteger count = new AtomicInteger();
        ObjectProperty<Stage> visibleStage = new SimpleObjectProperty<>();
        ScheduledService<Integer> service = new ScheduledService<Integer>() {
            @Override
            protected Task<Integer> createTask() {
                Task<Integer> task = new Task<Integer>() {
                    @Override 
                    public Integer call() {
                        return count.incrementAndGet();
                    }
                };
                return task ;
            }
        };

        service.setOnSucceeded(event -> {
            Stage lastStage = visibleStage.get();
            Stage stage = createWindowWithImage(service.getValue());
            visibleStage.set(stage);
            stage.setX(maxX - 480);
            stage.show();
            if (lastStage != null) {
                lastStage.close();
            }
//            System.gc();
        });

        service.setPeriod(Duration.seconds(1));
        return service;
    }


    private Stage createWindowWithImage(int count) {
        Stage stage = new Stage();
        ImageView image = createImage();
        Label label = new Label("Window "+count);
        label.setGraphic(image);
        label.setContentDisplay(ContentDisplay.BOTTOM);
        stage.setScene( new Scene(new StackPane(label), 480, 500) );
        return stage;
    }

    private ImageView createImage() {
        WritableImage img = new WritableImage(400, 400);
        Random rng = new Random();
        int x = rng.nextInt(40);
        int y = rng.nextInt(40);
        PixelWriter pw = img.getPixelWriter();
        for (int i = 0; i < 400; i++) {
            for (int j = 0 ; j < 400 ; j++) {
                if (i >= x*10 && i < (x+1)*10 && j >= y*10 && j < (y+1) * 10) {
                    pw.setColor(i, j, Color.CORNFLOWERBLUE);
                } else {
                    pw.setColor(i, j, Color.ANTIQUEWHITE);
                }
            }
        }
        return new ImageView(img);
    }

    private Pane createMemoryMonitor() {
        LongProperty totalMemory = new SimpleLongProperty(Runtime.getRuntime().totalMemory());
        LongProperty freeMemory = new SimpleLongProperty(Runtime.getRuntime().freeMemory());
        LongProperty maxMemory = new SimpleLongProperty(Runtime.getRuntime().maxMemory());
        NumberBinding usedMemory = totalMemory.subtract(freeMemory);

        Label usedMemoryLabel = new Label();
        usedMemoryLabel.textProperty().bind(usedMemory.asString("Used memory: %,d"));
        Label freeMemoryLabel = new Label();
        freeMemoryLabel.textProperty().bind(freeMemory.asString("Free memory: %,d"));
        Label totalMemoryLabel = new Label();
        totalMemoryLabel.textProperty().bind(totalMemory.asString("Total memory: %,d"));
        Label maxMemoryLabel = new Label();
        maxMemoryLabel.textProperty().bind(maxMemory.asString("Max memory: %,d"));

        Series<Number, Number> series = new Series<>();
        series.setName("Used memory");

        AtomicInteger time = new AtomicInteger();

        Timeline updateMemory = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
            totalMemory.set(Runtime.getRuntime().totalMemory());
            freeMemory.set(Runtime.getRuntime().freeMemory());
            maxMemory.set(Runtime.getRuntime().maxMemory());
            series.getData().add(new Data<>(time.incrementAndGet(), usedMemory.getValue()));
            if (series.getData().size() > 100) {
                series.getData().subList(0, series.getData().size() - 100).clear();
            }    
        }));
        updateMemory.setCycleCount(Animation.INDEFINITE);
        updateMemory.play();

        VBox labels = new VBox(usedMemoryLabel, freeMemoryLabel, totalMemoryLabel, maxMemoryLabel);
        labels.setAlignment(Pos.CENTER);

        NumberAxis xAxis = new NumberAxis();
        xAxis.setLabel("Time");
        xAxis.setForceZeroInRange(false);
        NumberAxis yAxis = new NumberAxis();
        yAxis.setLabel("Memory");
        LineChart<Number, Number> chart = new LineChart<Number, Number>(xAxis, yAxis);
        chart.setAnimated(false);
        chart.getData().add(series);

        BorderPane root = new BorderPane(chart, labels, null, null, null);

        return root;
    }

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