JavaFX перенаправлен System.out поток TextArea, работает только тогда, когда он не используется как компонент FXML с fixedID.Why?

Вопрос:

Так что это было довольно запутанно для меня. Я решил перенаправить консоль приложений в TextArea в своем интерфейсе.

Bud, когда я сделал это с Fixed TextArea (Fixed ID) в SceneBuilder, а затем аннотировал

@FXML
private TextArea consoleTextArea;

Ничего не происходит. Нет изменений в контенте. И да, я инициализировал его в конструкторе. И далее в инициализации. Это не рабочий код:

public class ConsoleController implements Initializable {

Thread t;
@FXML
private Label totalM;
@FXML
private Label freeM;
@FXML
private Label maxM;
@FXML
private TextArea consoleTextArea;

private Console console;
private PrintStream ps;


public ConsoleController() {
System.out.println("Called constructor");
totalM = new Label();
freeM = new Label();
maxM = new Label();
consoleTextArea = new TextArea();
console = new Console(consoleTextArea);
ps = new PrintStream(console, true);

}

@Override
public void initialize(URL location, ResourceBundle resources) {

redirectOutput(ps);


t = new Thread(() -> {
while (true) {
try {
Platform.runLater(() -> {
updateMemInfo();
});
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}

});
t.setPriority(Thread.MIN_PRIORITY);
t.setName("MemUpdateInfoThread");
t.setDaemon(true);
t.start();

}

private void updateMemInfo() {
totalM.setText("Total Memory (in bytes): " + Runtime.getRuntime().totalMemory());
freeM.setText("Free Memory (in bytes): " + Runtime.getRuntime().freeMemory());
maxM.setText("Max Memory (in bytes): " + Runtime.getRuntime().maxMemory());
}

private void redirectOutput(PrintStream prs) {
System.setOut(prs);
System.setErr(prs);
}

private void updateConsole(String text) {
for (int c : text.toCharArray()) {
try {
console.write(c);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

private class Console extends OutputStream {

private TextArea txtArea;

public Console(TextArea txtArea) {
this.txtArea = txtArea;
}

@Override
public void write(int b) throws IOException {
txtArea.appendText(String.valueOf((char) b));
}

}

}

Bud после некоторого edditing.I решил не использовать fxml id.And только поместить id на родительский элемент AnchorPane и добавил textArea в java-код.

  @FXML
private AnchorPane anchp;

private TextArea consoleTextArea;

//then added to anchor
anchp.getChildren().add(consoleTextArea);

рабочий код:

public class ConsoleController implements Initializable {

Thread t;
@FXML
private Label totalM;
@FXML
private Label freeM;
@FXML
private Label maxM;
@FXML
private AnchorPane anchp;

private TextArea consoleTextArea;

private Console console;
private PrintStream ps;

public ConsoleController() {
System.out.println("Called constructor");
totalM = new Label();
freeM = new Label();
maxM = new Label();
anchp=new AnchorPane();
consoleTextArea = new TextArea();
console = new Console(consoleTextArea);
ps = new PrintStream(console, true);

}

@Override
public void initialize(URL location, ResourceBundle resources) {

anchp.getChildren().add(consoleTextArea);
AnchorPane.setTopAnchor(consoleTextArea, 0d);
AnchorPane.setLeftAnchor(consoleTextArea, 0d);
AnchorPane.setRightAnchor(consoleTextArea, 0d);
AnchorPane.setBottomAnchor(consoleTextArea, 0d);

redirectOutput(ps);

t = new Thread(() -> {
while (true) {
try {
Platform.runLater(() -> {
updateMemInfo();
});
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}

});
t.setPriority(Thread.MIN_PRIORITY);
t.setName("MemUpdateInfoThread");
t.setDaemon(true);
t.start();

}

private void updateMemInfo() {
totalM.setText("Total Memory (in bytes): " + Runtime.getRuntime().totalMemory());
freeM.setText("Free Memory (in bytes): " + Runtime.getRuntime().freeMemory());
maxM.setText("Max Memory (in bytes): " + Runtime.getRuntime().maxMemory());
}

private void redirectOutput(PrintStream prs) {
System.setOut(prs);
System.setErr(prs);
}

private void updateConsole(String text) {
for (int c : text.toCharArray()) {
try {
console.write(c);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

private class Console extends OutputStream {

private TextArea txtArea;

public Console(TextArea txtArea) {
this.txtArea = txtArea;
}

@Override
public void write(int b) throws IOException {
txtArea.appendText(String.valueOf((char) b));
}

}

}

Почему я не смог сделать это с помощью fixedID на компоненте, который я использовал? Может ли кто-нибудь объяснить, что я сделал неправильно?

Лучший ответ:

И да, я инициализировал его в конструкторе.

Это точно проблема. Никогда не инициализируйте поля, которые вводятся в контроллер с помощью аннотации @FXML.

Если вы аннотируете поле с @FXML, FXMLLoader собирается инициализировать это поле экземпляром, объявленным в файле FXML, сопоставляя имя поля (“consoleTextArea”) с атрибутом fx:id. Очевидно, все это происходит после завершения конструктора, но до initialize() метода initialize(). Следовательно, consoleTextArea вы передали в свой Console конструктор, представляет собой другой экземпляр для того, к которому вы в конечном итоге к тому времени, когда initalize() метод initalize() (и когда обработчики событий вызывается позже).

Чтобы исправить это, полностью избавиться от конструктора и инициализировать другие части, которые вам нужны (т.е. вещи, которые не определены в вашем FXML) в методе initialize().

Что-то вроде:

public class ConsoleController implements Initializable {

    Thread t;
    @FXML
    private Label totalM;
    @FXML
    private Label freeM;
    @FXML
    private Label maxM;
    @FXML
    private TextArea consoleTextArea;

    private Console console;
    private PrintStream ps;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        console = new Console(consoleTextArea);
        ps = new PrintStream(console, true);

        redirectOutput(ps);


        t = new Thread(() -> {
            while (true) {
                try {
                    Platform.runLater(() -> {
                        updateMemInfo();
                    });
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }

        });
        t.setPriority(Thread.MIN_PRIORITY);
        t.setName("MemUpdateInfoThread");
        t.setDaemon(true);
        t.start();

    }

    // other methods as before...
}

Оцените статью
TechArks.Ru
Добавить комментарий