【问题标题】:Inconsistency between JLabel and JTextField when ComponentOrientation set to RTLComponentOrientation 设置为 RTL 时 JLabel 和 JTextField 不一致
【发布时间】:2014-12-18 08:59:24
【问题描述】:


关于摇摆中从右到左的组件方向,我有一个奇怪的问题 - JLabel 和 JTextField 在相同值的显示方面存在不一致。 附件是一个演示问题的SSCCE。

是不是我做错了什么?

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ComponentOrientation;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class GuiTest2 extends JFrame
{
    public GuiTest2()
    {
        super( "Test" );

        JLabel testLabel = new JLabel();
        testLabel.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
        testLabel.setText( "ca 12 בדיקה" );
        testLabel.setBorder( new LineBorder( Color.BLACK ) );

        JTextField testTextField = new JTextField();
        testTextField.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
        testTextField.setText( "ca 12 בדיקה" );
        testTextField.setBorder( new LineBorder( Color.BLACK ) );

        JPanel panel = new JPanel( new BorderLayout( 5, 5) );
        panel.setBorder( new EmptyBorder( 10, 10, 10, 10 ) );
        panel.add( testLabel, BorderLayout.NORTH );
        panel.add( testTextField, BorderLayout.SOUTH );

        setContentPane( panel );
        pack();
        setLocationRelativeTo( null );
        setVisible( true );
    }

    public static void main( String[] args )
    {
        SwingUtilities.invokeLater( new Runnable()
        {
            @Override
            public void run()
            {
                new GuiTest2();
            }
        } );
    }
}


这是上面代码的截图:

结果字符串不应该相同吗?

没有setComponentOrientation 我有以下( 相同):

【问题讨论】:

  • 根据 Javadocs:ComponentOrientation 类封装了语言敏感的方向,用于对组件或文本的元素进行排序。这种奇怪行为背后的原因可能是您用于显示值的语言。
  • 它非常适合纯英文单词。
  • 这两个组件使用相同的语言但它们的呈现方式不同,这似乎很奇怪

标签: java swing right-to-left


【解决方案1】:

简短的回答是JLabel 忽略componentOrientation

略长一点的答案...

文本最终呈现为基本 LTR 还是基本 RTL 取决于 TextLine 中的逻辑。如果文本上有属性,并且属性中包含双向嵌入的信息,则该信息用于设置默认的文本方向。这通常出现在 JTextPaneJTextField 之类的组件上,它们也基于 Document,可能具有相同的行为(尽管在今天之前,我根本不知道 JTextField 和 JTextArea 有任何属性,这会有某种意义。)

在信息不存在的情况下,从 Unicode 双向算法 (UAX #9) 中计算出来的逻辑在java.text.Bidi 中。该算法非常复杂,但基本上如果您的行不以强 RTL 字符开头,则默认情况下该行将被假定为 LTR。

可以说,setComponentOrientation() 应该告诉渲染器更改该默认值,因此我将其视为 Java 错误。

一种解决方法(假设您控制应用程序中所有标签的构造!)是在文本开头插入 \u202E:

    String text = "\u202Eca 12 \u05D1\u05D3\u05D9\u05E7\u05D4";

    JLabel testLabel = new JLabel();
    testLabel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT );
    testLabel.setText(text);
    testLabel.setBorder( new LineBorder( Color.BLACK ) );

如何插入字符串取决于方便:

  1. 检查 setText 的所有用法,如果其中任何一个可能以非 RTL 字符开头,请插入该字符。
  2. 查看资源包中的所有字符串格式,如果其中任何一个可能以非 RTL 字符开头,请将字符插入到消息格式中。 (当您控制字符串时,这听起来是一个很好的解决方案,但当您在第三方库中遇到此问题时,它就不那么好了。)
  3. JLabel 替换为可解决该问题的子类。这适用于所有 LAF,但同样,如果您在第三方库中遇到问题,您必须说服他们应用类似的修复程序。
  4. BasicLabelUI 替换为固定的子类,依此类推,以用于您打算支持的所有其他 LAF。就重复而言,这是一种痛苦,但该修复将自动适用于任何第三方使用的标签。

当然,当您发现问题时,可以根据具体情况应用上述任何方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-07
    • 2016-05-17
    • 2017-05-09
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多