Pengkodean UTF-8 untuk keluaran dari Konsol ke JavaFX TextArea
Saya ingin mengarahkan output di Console ke JavaFX TextArea, dan saya mengikuti saran di sini: JavaFX: Alihkan output konsol ke TextArea yang dibuat di SceneBuilder
Saya mencoba mengatur charset ke UTF-8 di PrintStream (), tetapi tidak terlihat begitu baik . Menyetel charset ke UTF-16 sedikit meningkatkannya, tetapi masih tidak terbaca .
Di Eclipse IDE, keluaran teks yang seharusnya di Konsol ternyata baik-baik saja:
KHA khởi đầu phiên giao dịch sáng nay ở mức 23600 điểm, khối lượng giao dịch trong ngày đạt 765 cổ phiếu, tương đương khoảng 18054000 đồng.
Controller.java
public class Controller {
@FXML
private Button button;
public Button getButton() {
return button;
}
@FXML
private TextArea textArea;
public TextArea getTextArea() {
return textArea;
}
private PrintStream printStream;
public PrintStream getPrintStream() {
return printStream;
}
public void initialize() {
textArea.setWrapText(true);
printStream = new PrintStream(new UITextOutput(textArea), true, StandardCharsets.UTF_8);
} // Encoding set to UTF-8
public class UITextOutput extends OutputStream {
private TextArea text;
public UITextOutput(TextArea text) {
this.text = text;
}
public void appendText(String valueOf) {
Platform.runLater(() -> text.appendText(valueOf));
}
public void write(int b) throws IOException {
appendText(String.valueOf((char) b));
}
}
}
UI.java
public class UI extends Application {
@Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Sample.fxml"));
Parent root = loader.load();
Controller control = loader.getController();
stage.setTitle("Title");
stage.setScene(new Scene(root));
stage.show();
control.getButton().setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
try {
System.setOut(control.getPrintStream());
System.setErr(control.getPrintStream());
System.out.println(
"KHA khởi đầu phiên giao dịch sáng nay ở mức 23600 điểm, khối lượng giao dịch trong ngày đạt 765 cổ phiếu, tương đương khoảng 18054000 đồng.");
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Sample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="339.0" prefWidth="468.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="main.Controller">
<center>
<TextArea fx:id="textArea" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
<right>
<Button fx:id="button" mnemonicParsing="false" onAction="#getButton" text="Button" BorderPane.alignment="CENTER" />
</right>
</BorderPane>
Saya masih baru mengenal Java jadi saya tidak terbiasa dengan cara kerja PrintStream atau OutputStream. Mohon maafkan ketidaktahuan saya.
Setiap saran dihargai.
Jawaban
Saya yakin masalah Anda disebabkan oleh kode ini:
public void write(int b) throws IOException {
appendText(String.valueOf((char) b));
}
Ini mengubah setiap byte individu menjadi karakter. Dengan kata lain, ini mengasumsikan setiap karakter diwakili oleh satu byte. Itu belum tentu benar. Beberapa pengkodean, seperti UTF-8 , dapat menggunakan beberapa byte untuk mewakili satu karakter. Mereka harus melakukannya jika mereka ingin dapat mewakili lebih dari 256 karakter.
Anda harus mendekode byte yang masuk dengan benar. Daripada mencoba melakukan ini sendiri, akan lebih baik mencari cara untuk menggunakan sesuatu seperti BufferedReader
. Untungnya itu mungkin dengan PipedInputStream
dan PipedOutputStream
. Sebagai contoh:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.io.UncheckedIOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
TextArea area = new TextArea();
area.setWrapText(true);
redirectStandardOut(area);
primaryStage.setScene(new Scene(area, 800, 600));
primaryStage.show();
System.out.println(
"KHA khởi đầu phiên giao dịch sáng nay ở mức 23600 điểm, khối lượng giao dịch trong ngày đạt 765 cổ phiếu, tương đương khoảng 18054000 đồng.");
}
private void redirectStandardOut(TextArea area) {
try {
PipedInputStream in = new PipedInputStream();
System.setOut(new PrintStream(new PipedOutputStream(in), true, UTF_8));
Thread thread = new Thread(new StreamReader(in, area));
thread.setDaemon(true);
thread.start();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private static class StreamReader implements Runnable {
private final StringBuilder buffer = new StringBuilder();
private boolean notify = true;
private final BufferedReader reader;
private final TextArea textArea;
StreamReader(InputStream input, TextArea textArea) {
this.reader = new BufferedReader(new InputStreamReader(input, UTF_8));
this.textArea = textArea;
}
@Override
public void run() {
try (reader) {
int charAsInt;
while ((charAsInt = reader.read()) != -1) {
synchronized (buffer) {
buffer.append((char) charAsInt);
if (notify) {
notify = false;
Platform.runLater(this::appendTextToTextArea);
}
}
}
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private void appendTextToTextArea() {
synchronized (buffer) {
textArea.appendText(buffer.toString());
buffer.delete(0, buffer.length());
notify = true;
}
}
}
}
Penggunaan di buffer
atas adalah upaya untuk menghindari membanjiri Thread Aplikasi JavaFX dengan tugas.
Beberapa hal lain yang perlu Anda pertimbangkan:
- Karena Anda menggunakan literal string, pastikan Anda menyimpan file sumber dengan UTF-8 dan mengompilasi kode dengan
-encoding UTF-8
. - Pastikan font yang Anda gunakan dengan
TextArea
can mewakili semua karakter yang Anda inginkan. - Ini mungkin Anda juga perlu menjalankan aplikasi dengan
-Dfile.encoding=UTF-8
tapi aku tidak yakin. Saya tidak melakukannya dan itu masih berhasil untuk saya.
Coba setel pengkodean JVM default Anda ke UTF-8.
java -Dfile.encoding=UTF-8 -jar YourJarfile.jar
Untuk lebih jelasnya lihat utas ini: Mengatur pengkodean karakter Java default
Jika Anda tidak ingin mengekspor file Anda, masuk ke Eclipse Preferences> General> Workspace dan setel pengkodean file Teks ke UTF-8 (atau pengkodean yang Anda inginkan).
Ada beberapa detail lainnya: Cara mengubah pengkodean file teks default di Eclipse