Некоторые символы Unicode в Java не отображаются в JTextField - PullRequest
0 голосов
/ 17 октября 2018

Недавно мы преобразовали базу данных Oracle одного из наших клиентов из Windows-1252 в Unicode (я не знаю, как им все-таки удалось с этим справиться; они сохранили много личных имен).

Все работаетну кроме некоторых персонажей.Это символ (s с точкой внизу), который позволяет проблеме войти в наш мир.Насколько я знаю, когда не указано, Java использует свои логические шрифты, чтобы найти шрифты, которые работают на каждой ОС (см. https://docs.oracle.com/javase/tutorial/2d/text/fonts.html).

. Я создал быстрый пример, который являетсяодин из https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html:

/*
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of Oracle or the names of its
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* TextDemo.java requires no other files. */
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class Chartest extends JPanel implements ActionListener {
    protected JTextField textField;
    protected JTextArea textArea;
    private final static String newline = "\n";

    public Chartest() {
        super(new GridBagLayout());
        // UIManager.getLookAndFeelDefaults().put("TextField.font", new Font("Arial",
        // Font.PLAIN, 14));
        textField = new JTextField(20);
        textField.addActionListener(this);

        textArea = new JTextArea(5, 20);
        textArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(textArea);

        // Add Components to this panel.
        GridBagConstraints c = new GridBagConstraints();
        c.gridwidth = GridBagConstraints.REMAINDER;

        c.fill = GridBagConstraints.HORIZONTAL;
        add(textField, c);

        c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.weighty = 1.0;
        add(scrollPane, c);
    }

    public void actionPerformed(ActionEvent evt) {
        String text = textField.getText();
        textArea.append(text + newline);
        textField.selectAll();

        // Make sure the new text is visible, even if there
        // was a selection in the text area.
        textArea.setCaretPosition(textArea.getDocument().getLength());
    }

    /**
     * Create the GUI and show it. For thread safety,
     * this method should be invoked from the
     * event dispatch thread.
     */
    private static void createAndShowGUI() {
        // Create and set up the window.
        JFrame frame = new JFrame("TextDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Add contents to the window.
        frame.add(new Chartest());

        // Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        // Schedule a job for the event dispatch thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

Единственное, что я добавил, это следующая строка:

// UIManager.getLookAndFeelDefaults().put("TextField.font", new Font("Arial", Font.PLAIN, 14));

Без этой строки становится квадратом при вводе в текстовое полеЕсли вы раскомментируете эту строку, она будет работать. Если посмотреть на fontconfig.properties.src в папке lib Java, все логические шрифты указывают на шрифты, которые могут отображать : Times, Courier, Arial. Я переименовал файл в fontconfig.propertiesи изменил все на Arial, чтобы переопределить значения по умолчанию. Это ничего не изменило.

Это также не работает:

UIManager.getLookAndFeelDefaults().put("TextField.font", new Font("Dialog", Font.PLAIN, 14));

Хотя Dialog, очевидно, ссылается на Arial вfontconfig.properties.src.
Что я пропускаю? Я на Java 10.

1 Ответ

0 голосов
/ 17 октября 2018

Рендеринг логических шрифтов кажется полем загадок.В одном тестовом прогоне я получил правильное отображение соответствующих символов в пределах JTextArea, но не в пределах JTextField, в то время как textArea.getFont()==textField.getFont() оценивается как true!

* fontconfig.properties.src относится к Arial, но также содержит следующую строку:

exclusion.alphabetic=0700-1e9f,1f00-2017,2020-20ab,20ad-20b8,20bb-20bc,20be-f8ff

и и (U+1e63 и U+1e62) находятся именно в этом диапазоне.

Я не знаюНе известно, где эти явно «буквенные» символы должны заканчиваться, когда их здесь исключают. В этом документе просто говорится:

Используется, если шрифт с большим набором символов необходимо поместить в начале последовательности поиска (например, из соображений производительности), нонекоторые символы, которые он поддерживает, должны быть нарисованы другим шрифтом.

Но я понятия не имею, почему эти символы не должны отображаться с первым шрифтом, настроенным для «алфавитного», и каким другим шрифтом впоследовательность поиска должна их визуализировать.

Кроме того, этот диапазон выглядит произвольно произвольным, то есть подразумевает, что, хотя и находятся в исключенном диапазоне, и - нети может быть отображено правильно.

Когда вы превращаете эту строку в комментарий, то есть

#exclusion.alphabetic=0700-1e9f,1f00-2017,2020-20ab,20ad-20b8,20bb-20bc,20be-f8ff

, проблема исчезает.

У меня такое ощущение, что первоначальное предложение об исключениивызывал рендеринг с использованием встроенного шрифта Lucida, который не может отображать эти символы.В JDK 11 эта линия исключения все еще существует, и ее обновленная версия:

exclusion.alphabetic=0700-1cff,1d80-1e9f,1f00-2017,2020-20ab,20ad-20b8,20bb-20bc,20be-f8ff

по-прежнему охватывает и (U+1e63 и U+1e62).Но шрифты Lucida были удалены, следовательно, жестко закодированные ссылки на эти шрифты в коде AWT также должны быть удалены.

В результате изменений, внесенных между JDK 10 и JDK 11, символы и отображаются правильно.

Таким образом, суть в том, что вместо попытки исправить конфигурацию AWT JDK 10 вы также можете просто обновить ее до JDK 11.

Это относится как к OpenJDK 11, так и к Oracle JDK 11. Их файлы конфигурации шрифтов отличаются только комментарием к заголовку лицензии…

...