Проблема с переполнением символов юникода в JTextPane (Swing) - PullRequest
0 голосов
/ 09 мая 2020

Я хочу использовать символы Unicode для визуализации игральных карт для игры в покер. Я печатаю их в JTextPane отдельными строками. Как вы можете видеть на первом изображении, они иногда имеют тенденцию переходить на другие строки. Я вывожу карточки тем же способом, поэтому действительно странно, что это случается лишь иногда. Это совершенно случайно.

У каждой карты один и тот же стиль, установленный с помощью SimpleAttributeSet. Похоже, что высота строки у карточек меньше, чем должна быть. Итак, я подумал, что Swing может плохо поддерживать символы Unicode, поэтому я добавил символ «M» между карточками с тем же стилем, что и карточки. После этого вроде все заработало.

Это пример того, как я распечатываю карты (карты печатаются в al oop):

StyledDocument doc = jTextPane.getStyledDocument();

doc.insertString(doc.getLength(), "Karty na stole: \n", attributeSet);

doc.insertString(doc.getLength(), "???? \n" , attributeSetForCards);

Карты иногда выходят за пределы своих строк: Cards are sometimes overflowing from their lines

Здесь вы можете увидеть, что они вычислены правильно: Here you can see they are correctly outputed

Код ниже является примером этой ошибки, но ошибка возникает только иногда. Я заметил, что Thread.sleep () имеет какое-то влияние, потому что вероятность того, что это произойдет, увеличилась с этой командой. Как видно из приведенного ниже кода, команды Thread.sleep () нет, и ошибка все равно появляется.

(я изменил кодировку карт на букву «M»)

Вот пример кода:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class StackOverflowProblem {

    public static void main(String[] args) throws BadLocationException {

        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JTextPane textPane = new JTextPane();
        textPane.setEditable(false);

        StyledDocument doc = textPane.getStyledDocument();

        SimpleAttributeSet keyWord = new SimpleAttributeSet();
        SimpleAttributeSet attributeSet = new SimpleAttributeSet();

        StyleConstants.setBold(keyWord, true);

        StyleConstants.setFontSize(attributeSet, 100);
        StyleConstants.setForeground(attributeSet, Color.RED);        

        JScrollPane sp = new JScrollPane(textPane);

        frame.getContentPane().add(sp);
        frame.setVisible(true);

        int x = 0;

        while (x < 100) {
            x++;
            doc.insertString(doc.getLength(), "Karty na stole: " + "\n", keyWord);
            StyleConstants.setForeground(attributeSet, Color.RED);

            for (int i = 0; i < 5; i++) {
                doc.insertString(doc.getLength(), "M", attributeSet);
                if (i > 1) {
                    StyleConstants.setForeground(attributeSet, Color.BLACK);
                }
            }

            doc.insertString(doc.getLength(), "\n", keyWord);

            doc.insertString(doc.getLength(), "Karty na stole: " + "\n", keyWord);

            for (int i = 0; i < 2; i++) {
                doc.insertString(doc.getLength(), "M", attributeSet);
            }

            doc.insertString(doc.getLength(), "\n", keyWord);

        }
    }


}

Альтернативный код: (?)

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

public class StackOverflowProblem {

    public static void main(String[] args) throws BadLocationException {
        JFrame frame = new JFrame();
        frame.setSize(1500, 600);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JTextPane textPane = new JTextPane();
        textPane.setEditable(false);

        StyledDocument doc = textPane.getStyledDocument();

        SimpleAttributeSet keyWord = new SimpleAttributeSet();
        SimpleAttributeSet attributeSet = new SimpleAttributeSet();

        StyleConstants.setBold(keyWord, true);

        StyleConstants.setFontSize(attributeSet, 100);
        StyleConstants.setFontFamily(attributeSet, getFontFamily());
        StyleConstants.setForeground(attributeSet, Color.RED);

        JScrollPane sp = new JScrollPane(textPane);

        frame.getContentPane().add(sp);
        frame.setVisible(true);

        String[][] obrazkyKariet = new String[4][14];
        for (int ii = 0; ii < 14; ii++) {
            obrazkyKariet[0][ii] = new String(Character.toChars(ii + 127137));
        }
        for (int ii = 0; ii < 14; ii++) {
            obrazkyKariet[1][ii] = new String(Character.toChars(ii + 127153));
        }
        for (int ii = 0; ii < 14; ii++) {
            obrazkyKariet[2][ii] = new String(Character.toChars(ii + 127169));
        }
        for (int ii = 0; ii < 14; ii++) {
            obrazkyKariet[3][ii] = new String(Character.toChars(ii + 127185));
        }

        doc.insertString(doc.getLength(), "Karty na stole: " + "\n", keyWord);

        StyleConstants.setForeground(attributeSet, Color.RED);

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 14; j++) {
                if (i == 0 || i == 3) {
                    StyleConstants.setForeground(attributeSet, Color.BLACK);
                } else {
                    StyleConstants.setForeground(attributeSet, Color.RED);
                }
                doc.insertString(doc.getLength(), obrazkyKariet[i][j], attributeSet);
            }
            doc.insertString(doc.getLength(), "\n", keyWord);
        }
    }

    public static String getFontFamily() {
        Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        for (Font font : fonts) {
            if (font.canDisplay(127137)) {
                System.out.println("First compatible font: " + font.getFamily());
                return font.getFamily();
            }
        }
        return "";
    }
}

1 Ответ

3 голосов
/ 10 мая 2020

Swing является однопоточным.

Таким образом, создание всех компонентов Swing и обновления компонентов или его модели должны выполняться на Event Dispatch Thread (EDT), иначе могут возникнуть случайные проблемы.

Похоже, что здесь происходит то, что документ не был полностью обновлен до вызова другого insertString(…) метода и некоторый текст не вставляется в надлежащее место в документе.

Прочтите раздел учебника Swing на Concurrency для получения дополнительной информации о EDT.

Итак, решение состоит в том, чтобы разместить свой код для выполнения на EDT. Код должен быть примерно таким:

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class StackOverflowProblem {

    private static void createAndShowGUI() throws Exception
    {
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JTextPane textPane = new JTextPane();
        textPane.setEditable(false);

        StyledDocument doc = textPane.getStyledDocument();

        SimpleAttributeSet keyWord = new SimpleAttributeSet();
        SimpleAttributeSet attributeSet = new SimpleAttributeSet();

        StyleConstants.setBold(keyWord, true);

        StyleConstants.setFontSize(attributeSet, 100);
        StyleConstants.setForeground(attributeSet, Color.RED);

        JScrollPane sp = new JScrollPane(textPane);

        frame.getContentPane().add(sp);
        frame.setVisible(true);

        int x = 0;

        while (x < 100) {
            x++;
            doc.insertString(doc.getLength(), "Karty na stole: " + "\n", keyWord);
            StyleConstants.setForeground(attributeSet, Color.RED);

            for (int i = 0; i < 5; i++) {
                doc.insertString(doc.getLength(), "M", attributeSet);
                if (i > 1) {
                    StyleConstants.setForeground(attributeSet, Color.BLACK);
                }
            }

            doc.insertString(doc.getLength(), "\n", keyWord);

            doc.insertString(doc.getLength(), "Karty na stole: " + "\n", keyWord);

            for (int i = 0; i < 2; i++) {
                doc.insertString(doc.getLength(), "M", attributeSet);
            }

            doc.insertString(doc.getLength(), "\n", keyWord);

        }
    }

    public static void main(String[] args) throws Exception
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    createAndShowGUI();
                }
                catch(Exception e) { System.out.println(e); }
            }
        });
    }
}

invokeLater(…) помещает код в EDT.

...