package com.cpex.javafx.util; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Skin; import javafx.scene.control.TextInputControl; import javafx.stage.Window; import javafx.stage.WindowEvent; import com.sun.javafx.scene.control.skin.TextInputControlSkin; public class FxBugs { public static void installMemoryLeakWorkaround(TextInputControl control) { TextControlMemoryLeakWorkaround workaround = new TextControlMemoryLeakWorkaround(control); workaround.install(); } private static class TextControlMemoryLeakWorkaround implements ChangeListener, EventHandler { private final TextInputControl control; private Scene scene; private Window window; public TextControlMemoryLeakWorkaround(TextInputControl control) { this.control = control; scene = null; window = null; } public void install() { control.sceneProperty().addListener(this); setScene(control.getScene()); } @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { if (observable == control.sceneProperty()) { setScene(control.getScene()); } else if (scene != null && observable == scene.windowProperty()) { setWindow(scene.getWindow()); } } @Override public void handle(WindowEvent event) { applyWorkaround(); } private void setScene(Scene scene) { if (this.scene != scene) { Window window = null; if (this.scene != null) { this.scene.windowProperty().removeListener(this); } this.scene = scene; if (this.scene != null) { this.scene.windowProperty().addListener(this); } setWindow(window); } } private void setWindow(Window window) { if (this.window != window) { boolean hadWindow = false; if (this.window != null) { this.window.removeEventFilter(WindowEvent.WINDOW_HIDING, this); hadWindow = true; } this.window = window; if (this.window != null) { this.window.addEventFilter(WindowEvent.WINDOW_HIDING, this); } else if (hadWindow) { applyWorkaround(); } } } private void applyWorkaround() { Skin skin = control.getSkin(); if (skin instanceof TextInputControlSkin) { TextInputControlSkin ticSkin = (TextInputControlSkin) skin; try { ticSkin.setCaretAnimating(false); } catch (Exception e) { // ignored } try { ticSkin.dispose(); } catch (Exception e) { // ignored } } } } // end class TextControlMemoryLeakWorkaround private FxBugs() { // empty } }