【问题标题】:Problem with overflowing unicode characters in JTextPane (Swing)JTextPane (Swing) 中溢出 unicode 字符的问题
【发布时间】:2020-05-08 21:02:05
【问题描述】:

我想使用 unicode 字符来可视化扑克游戏的扑克牌。我在 JTextPane 中单独打印它们。正如您在第一张图片中看到的那样,它们有时会溢出到其他行。我使用相同的方法输出卡片,所以它只是偶尔发生,这真的很奇怪。这完全是随机的。

每张卡片都通过 SimpleAttributeSet 设置相同的样式。看起来卡片的行高比它应该的要小。所以我在想 Swing 可能对 unicode 字符的支持不好,所以我在卡片之间添加了一个“M”字符,与卡片的样式相同。在那之后,一切似乎都运行良好。

这是我如何打印卡片的示例(卡片循环打印):

StyledDocument doc = jTextPane.getStyledDocument();

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

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

卡片有时会从他们的行中溢出:

在这里您可以看到它们已正确输出:

下面的代码是该错误的示例,但该错误只是偶尔发生。我注意到 Thread.sleep() 对它有一些影响,因为这个命令增加了发生这种情况的可能性。正如您在下面的代码中看到的那样,没有 Thread.sleep() 命令,并且无论如何都会出现错误。

(我将卡片的 unicode 更改为字母“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 "";
    }
}

【问题讨论】:

  • 发布您的minimal reproducible example 以证明问题。
  • 你只需复制粘贴即可。 - 没有 import 语句,没有类定义,没有 main 方法。我无法复制/粘贴/编译/测试。如果您已经完成所有这些以确保它确实编译并复制了问题,那么请发布该代码。不要让每个阅读您的问题的人都重复您已经完成的工作。
  • 您假设人们使用 IDE。我不。这就是 MRE 的意义所在。不要做假设。发布每个人都可以测试的代码。这并不意味着人们(比如我)会有答案,但至少这让他们很容易快速浏览。另外,关于@AndrewThompson,评论,这仍然是“MRE”吗?必要的属性集是否证明了问题,或者它们是否会导致问题。如果它们没有引起问题,那么所有逻辑都是不必要的。 MRE 的重点是忘记您的应用程序并隔离问题。任何线索都会有所帮助。
  • “现在每个人都可以复制粘贴了。” 这绝对是一个进步。但不幸的是,Unicode 字符意味着直接复制/粘贴不起作用。 (这与编码问题有关。)我尝试更改源代码以使用 Unicode 代码点制作卡片,但随后发现此处用于文本窗格的默认字体不会呈现它们,因此将其更改为使用系统上支持这些字符的第一个字体。 然后因为我无法确定正在使用哪些卡片,我只是将整个套牌放入减少的迭代次数到 1 中,以查看..
  • .. 他们渲染as expected。呃.. 可能问题与所使用的字体有关。这里选择的字体是“DejaVu Sans”。您希望我发布我正在使用的来源,以便您可以进一步调查吗?

标签: java swing unicode jtextpane


【解决方案1】:

Swing 是单线程的。

所以所有 Swing 组件的创建和组件或其模型的更新必须在Event Dispatch Thread (EDT) 上完成,否则可能会出现随机问题。

这里发生的情况似乎是,在调用另一个 insertString(…) 方法之前,文档尚未完全更新,并且某些文本未插入到文档中的正确位置。

阅读 Concurrency 上的 Swing 教程部分,了解有关 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 上。

【讨论】:

  • 看来你解决了我的问题。非常感谢您的帮助和对我的耐心。
猜你喜欢
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 2011-07-18
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 2017-07-02
  • 1970-01-01
相关资源
最近更新 更多