简体   繁体   中英

(Java) Character 'é' is displayed wrong in JTextArea

first time posting something and I have a question.

I'm using JFrame and JTextArea, redirecting my console output into the JTextArea. In the console it shows correctly. This is the code of redirecting:

public PrintStream redirectOut() {
    
    OutputStream out = new OutputStream() {
        @Override
        
        public void write(int b) throws IOException {
            String k = String.valueOf((char) b);
            byte[] o = k.getBytes();
            String text = new String(o,"Cp1252");
            output.append(k);
        }
    };
    PrintStream ps = new PrintStream(out);
    System.setOut(ps);
    System.setErr(ps);
    return ps;
}

If i put the character 'é' the same way into the TextArea it shows correctly, but not like this. Why is that? Someone has a solution? (output is my JTextArea) Thanks!

It's not quite clear what your multi-step conversion is trying to achieve.

The write(int) method will receive a single byte , for some reasons passed as int . Since the byte originates from a PrintStream constructed as new PrintStream(out) , it will be encoded in the system's default encoding.

One way to convert it back to a String using the same (system default) encoding would be

byte[] array = { (byte) b };
String text = new String(array);

However, there are some things to keep in mind

  1. The system default encoding might not support all unicode characters. Hence, the code above is correct, but still may cause data loss. You should therefore not rely on the system default encoding, but use an explicit encoding capable of handling all characters, eg UTF-8, for both sides.

  2. This approach can't handle multi-byte encodings as when trying to convert a single byte of a multi byte sequence back to a string you'll end up at invalid or wrong characters. A portable program can not assume to know whether the system default encoding is multi-byte or not. When following the advice of point 1, you'll always end up at a multi-byte encoding. You need a solution that can accumulate multiple bytes before converting them to a string. That will even improve the efficiency.

Here is a complete solution:

public class PrintToTextArea extends ByteArrayOutputStream implements Runnable
{
  public static PrintStream create(JTextArea ta)
  {
    try
    {
      return new PrintStream(new PrintToTextArea(ta), true, "UTF-8");
    }
    catch(UnsupportedEncodingException ex)
    {
      throw new AssertionError("UTF-8 should always be supported", ex);
    }
  }

  private final JTextArea target;

  private PrintToTextArea(JTextArea ta)
  {
    super(100);
    target = ta;
  }
  @Override
  public void flush()
  {
    if(EventQueue.isDispatchThread()) run(); else EventQueue.invokeLater(this);
  }
  @Override
  public synchronized void run()
  {
    target.append(new String(buf, 0, count, StandardCharsets.UTF_8));
    count = 0;
  }
}

It uses UTF-8 on both sides, to handle all unicode characters, and gathers bytes in the buffer of a ByteArrayOutputStream , to create a new String and append it when flush is called, which happens automatically on newlines or when flush has been called explicitly.

You can try it with something like

public static void main(String[] args) {
  try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
  catch(ReflectiveOperationException | UnsupportedLookAndFeelException ex) {}

  JFrame f = new JFrame();
  JTextArea ta = new JTextArea(40, 60);
  f.setContentPane(new JScrollPane(ta));
  PrintStream ps = PrintToTextArea.create(ta);
  System.setOut(ps);
  System.setErr(ps);
  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  f.pack();
  f.setVisible(true);

  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  Thread.dumpStack();
  System.out.println("È");
  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  System.out.println("ÄÖÜ");
  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  System.out.println("\u263a   \ud83d\ude80");
  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM