java - Changelistener not triggered in Console but by GUI -
i have task wich should runnable , updateable on console , gui. consider task written as
public static task<void> dostuff() { task<void> task; task = new task<void>() { final int totalsteps = 4; @override public void call() throws exception { updateprogress(0, totalsteps); updatemessage("1"); action(1); updateprogress(0, totalsteps); updatemessage("2"); action(2); //etc.. return null; } }; new thread(task) .start(); return task; } with bonding progress , message property within javafx gui, works expected , gui gets updated according progress. within cli, tried build simple progress bar wich updates user operation progress
private static void progressbar(task task) { task.progressproperty().addlistener((new changelistener() { @override public void changed(observablevalue observable, object oldvalue, object newvalue) { // return line beginning system.out.print("\r"); int percentage = (int) (100 * task.progressproperty().get()); system.out.format("[%3d%%] %s", percentage, task.messageproperty().get()); if (percentage == 100) { system.out.println("finished"); } } })); } }
as far see debugging, change listeners changed method not triggered. did set wrong it? finished print @ end not written.
as stated in comments, updates properties in javafx task performed on fx application thread. thread thread used render javafx scene graph , started javafx toolkit when launched. if javafx toolkit not running, thread won't started , properties not updated.
if want can run in background needs functional outside of javafx application, should use threading facilities not dependent on javafx. in case can implement runnable or callable. if want provide notifications when state changes, create callback, called when state changes. callbacks best represented using interfaces java.util.function package.
in case show, looks need message , progress together, use biconsumer<string, integer>.
public class dostuff implements runnable { private final int totalsteps ; private biconsumer<string, integer> update ; public dostuff(int totalsteps) { this.totalsteps = totalsteps ; } public void setupdate(biconsumer<string integer> update) { this.update = update ; } @override public void run() { if (update != null) { update.accept("0", 0) ; } (int = 1 ; <= totalsteps ; i++) { action(i); if (update != null) { update.accept(integer.tostring(i), i); } } } private void action(int i) { // ... } public int gettotalsteps() { return totalsteps() ; } } and do
public void progressbar(dostuff dostuff) { dostuff.setupdate((s, p) -> { // return line beginning system.out.print("\r"); int percentage = 100 * p / dostuff.gettotalsteps(); system.out.format("[%3d%%] %s", percentage, s); if (percentage == 100) { system.out.println("finished"); } }); } and execute in background thread
new thread(dostuff).start(); if wanted use in javafx environment, can, make sure callback updates ui components on fx application thread:
dostuff dostuff = ... ; dostuff.setupdate((s, p) -> platform.runlater(() -> { label.settext(s); double progress = 1.0 * p / dostuff.gettotalsteps(); progressbar.setprogress(p); })); it's reasonably easy create task<void> wraps this, , exposes progress , message in usual javafx way:
dostuff dostuff = ... ; task<void> dostufftask = new task<void>() { @override protected void call() { dostuff.setupdate((s, p) -> { updateprogress(p, dostuff.gettotalsteps()); updatemessage(s); }); dostuff.run(); return null ; } }; then do
progressbar.progressproperty().bind(dostufftask.progressproperty()); label.textproperty().bind(dostufftask.messageproperty()); thread t = new thread(dostufftask); t.setdaemon(true); t.start(); as usual.
Comments
Post a Comment