UTF-8-Codierung für die Ausgabe von der Konsole an JavaFX TextArea

Dec 22 2020

Ich möchte die Ausgabe in Console nach JavaFX TextArea umleiten und folge hier einem Vorschlag: JavaFX: Konsolenausgabe nach TextArea umleiten, das in SceneBuilder erstellt wurde

Ich habe versucht, den Zeichensatz in PrintStream () auf UTF-8 zu setzen, aber er sieht nicht so gut aus . Wenn Sie den Zeichensatz auf UTF-16 setzen, wird er etwas verbessert, ist aber immer noch unleserlich .

In der Eclipse-IDE ist die angebliche Textausgabe in der Konsole in Ordnung:

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>

Ich bin noch neu in Java, daher weiß ich nicht, wie genau PrintStream oder OutputStream funktionieren. Bitte entschuldigen Sie meine Unwissenheit.

Jeder Vorschlag wird geschätzt.

Antworten

1 Slaw Dec 23 2020 at 03:29

Ich glaube, Ihr Problem wird durch diesen Code verursacht:

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

Dies wandelt jedes einzelne Byte in ein Zeichen um. Mit anderen Worten, es wird davon ausgegangen, dass jedes Zeichen durch ein einzelnes Byte dargestellt wird. Das ist nicht unbedingt wahr. Einige Codierungen, wie z. B. UTF-8 , verwenden möglicherweise mehrere Bytes, um ein einzelnes Zeichen darzustellen. Sie müssen, wenn sie mehr als 256 Zeichen darstellen möchten.

Sie müssen die eingehenden Bytes ordnungsgemäß dekodieren. Anstatt zu versuchen, dies selbst zu tun, wäre es besser, einen Weg zu finden, so etwas zu benutzen BufferedReader. Zum Glück ist das mit PipedInputStreamund möglich PipedOutputStream. Beispielsweise:

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;
      }
    }
  }
}

Die Verwendung von bufferoben ist ein Versuch, zu vermeiden, dass der JavaFX-Anwendungsthread mit Aufgaben überflutet wird .

Einige andere Dinge, die Sie berücksichtigen müssen:

  • Da Sie ein Zeichenfolgenliteral verwenden, stellen Sie sicher, dass Sie sowohl die Quelldatei mit UTF-8 speichern als auch den Code mit kompilieren -encoding UTF-8.
  • Stellen Sie sicher, dass die Schriftart, die Sie mit TextAreaverwenden, alle gewünschten Zeichen darstellen kann.
  • Es ist möglich, dass Sie die Anwendung auch ausführen müssen, -Dfile.encoding=UTF-8aber ich bin mir nicht sicher. Ich habe es nicht getan und es hat immer noch bei mir funktioniert.
Nickitiki Dec 22 2020 at 15:47

Versuchen Sie, Ihre Standard-JVM-Codierung auf UTF-8 festzulegen.

java -Dfile.encoding=UTF-8 -jar YourJarfile.jar

Weitere Informationen finden Sie in diesem Thread: Festlegen der Standard-Java-Zeichenkodierung

Wenn Sie Ihre Datei nicht exportieren möchten, gehen Sie zu Ihren Eclipse- Einstellungen> Allgemein> Arbeitsbereich und setzen Sie die Codierung der Textdatei auf UTF-8 (oder die Codierung, die Sie haben möchten ).

Es gibt noch einige weitere Details: So ändern Sie die Standardcodierung von Textdateien in Eclipse