如何在不使用 HTML 的情况下向 JLabel 添加换行符

Posted

技术标签:

【中文标题】如何在不使用 HTML 的情况下向 JLabel 添加换行符【英文标题】:How to add a newline to JLabel without using HTML 【发布时间】:2011-11-12 00:27:03 【问题描述】:

如何在JLabel 中添加新行?我知道如果我使用简单的 html,它会起作用。但如果我使用 HTML,JLabel 不会显示嵌入应用程序的字体。我正在使用方法嵌入字体 - createFont() 并使用 JLabel.setFont() 来应用字体。

【问题讨论】:

【参考方案1】:

SwingX 支持多行标签:

   JXLabel label = new JXLabel();
   label.setLineWrap(true);

【讨论】:

在使用多行文本时,JXLabel 是否有“正确的”基线?请注意,“正确”对不同的人可能意味着不同的东西;-) @jfpoilpret - 不知道。什么是正确的基线? 对我来说,正确的基线是标签第一行第一个字符的基线。但是我敢肯定,您会发现其他人更喜欢以标签的整个高度为中心的基线。其他人可能还希望基线是标签中最后一行的第一个字符的基线。这实际上取决于人们希望标签在他们的布局中如何对齐。我认为我的第一个建议最有意义。【参考方案2】:

我认为没有直接(和简单)的方式来使用多行执行 JLabel 而不会重复到 HTML。您可以改用 JTextArea。

JTextArea textArea = new JTextArea();
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setOpaque(false);
textArea.setBorder(BorderFactory.createEmptyBorder());
add(textArea, BorderLayout.CENTER);

它应该看起来几乎一样。如果不同的组件有不同的字体,可以添加下面一行,保证JTextArea的字体和JLabel一致

textArea.setFont(UIManager.getFont("Label.font"));

希望这会有所帮助。

【讨论】:

我可以对齐 JTextArea 的文本吗?? 查看这个帖子***.com/questions/3213045/…【参考方案3】:

我正在使用方法嵌入字体 - createFont()) 并使用 JLabel.setFont() 来应用字体。

尝试在 HTML 中设置它,如 here 所示。

【讨论】:

从我的观点来看,使用 HTML 的主要问题是基线的丢失,现在大多数 LayoutManagers 都在使用它(恕我直言,这是一个很好的观点)【参考方案4】:

据我回忆,JLabel 最初并非用于多行文本。您需要覆盖各种渲染方法才能手动进行文本行拆分。

如果您想要多行标签,也许您应该使用不可编辑的 JTextArea。

【讨论】:

【参考方案5】:

1) 如果你想在不使用 JLabel 的情况下多行 JComponents,那么你必须像 JTextArea、JTextPane、JEditorPane 一样寻找 TextComponent,如果不应该是可编辑的,那么 myTextComponent#setEditable(false);

2) 我从未发现 Swing 中的 Html & Font & Color 有问题,例如:

import java.awt.Color;
import java.awt.Font;
import javax.swing.*;

public class ButtonFg extends JFrame 

    private static final long serialVersionUID = 1L;

    public ButtonFg() 
        JButton button = new JButton("<html> - myText <br>"
                + " - myText <br>"
                + " - myText <br>"
                + " - myText </html>");
        button.setForeground(Color.blue);
        button.setFont(new Font("Serif", Font.BOLD, 28));
        button.setFocusPainted(false);
        add(button);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocation(150, 150);
        pack();
    

    public static void main(String[] args) 
        SwingUtilities.invokeLater(new Runnable() 

            @Override
            public void run() 
                new ButtonFg().setVisible(true);
            
        );
    

【讨论】:

【参考方案6】:

以下大部分代码取自 BasicLabelUI 和/或 WindowsLabelUI,但我添加了代码以使其适用于多行。这是我可以开始工作的最少复制代码量。您可以使用 setSeparator 或通过更改 LinesAndIndex 实例化的默认值来设置行之间的分隔符。我没有对此进行广泛的测试,但到目前为止它对我有用。使用 HTML 时,助记符不起作用,所以我创建了这个。如果您有更好的方法来完成此操作,请更正代码。

    import com.sun.java.swing.plaf.windows.WindowsLabelUI;
    import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
    import java.awt.Color;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Insets;
    import java.awt.Rectangle;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.Icon;
    import javax.swing.JComponent;
    import javax.swing.JLabel;
    import javax.swing.UIManager;
    import javax.swing.plaf.LabelUI;
    import javax.swing.plaf.basic.BasicGraphicsUtils;
    import javax.swing.plaf.basic.BasicHTML;
    import javax.swing.text.View;

    public class MultiLineLabelUI extends WindowsLabelUI 
        private static MultiLineLabelUI multiLineLabelUI;
        private LinesAndIndex lai = new LinesAndIndex(',');
        private Rectangle paintIconR = new Rectangle();
        private Rectangle paintTextR = new Rectangle();
        public static LabelUI createUI(JComponent c) 
            if (multiLineLabelUI == null) 
                multiLineLabelUI = new MultiLineLabelUI();
            
            return multiLineLabelUI;
        
        private int getBaseline(JComponent c, int y, int ascent, int w, int h) 
            View view = (View) c.getClientProperty(BasicHTML.propertyKey);
            if (view != null) 
                int baseline = BasicHTML.getHTMLBaseline(view, w, h);
                if (baseline < 0) 
                    return baseline;
                
                return y + baseline;
            
            return y + ascent;
        
        public char getSeparator() 
            return lai.getSeparator();
        
        public void setSeparator(char ch) 
            lai.setSeparator(ch);
        
        private String layout(JLabel label, FontMetrics fm,
                int width, int height, int lineCnt, int curLine, String text) 
            Insets insets = label.getInsets(null);
            Icon icon = (label.isEnabled()) ? label.getIcon()
                    : label.getDisabledIcon();
            Rectangle paintViewR = new Rectangle();
            paintViewR.width = width - (insets.left + insets.right);
            paintViewR.height = (height - (insets.top + insets.bottom)) / lineCnt;
            paintViewR.x = insets.left;
            paintViewR.y = insets.top + (paintViewR.height * curLine);
            paintIconR.x = 0;
            paintIconR.y = 0;
            paintIconR.width = 0;
            paintIconR.height = 0;
            paintTextR.x = 0;
            paintTextR.y = 0;
            paintTextR.width = 0;
            paintTextR.height = 0;
            return layoutCL(label, fm, text, icon, paintViewR, paintIconR,
                    paintTextR);
        
        protected void paintEnabledText(JLabel l, Graphics g,
                String s, int textX, int textY, int curLine) 
            int mnemonicIndex = lai.getMnemonicIndex();
            // W2K Feature: Check to see if the Underscore should be rendered.
            if (WindowsLookAndFeel.isMnemonicHidden() == true) 
                mnemonicIndex = -1;
            
            if (curLine != lai.getMnemonicLineIndex()) 
                mnemonicIndex = -1;
            

            g.setColor(l.getForeground());
            BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemonicIndex,
                    textX, textY);
        
        protected void paintDisabledText(JLabel l, Graphics g,
                String s, int textX, int textY, int curLine) 
            int mnemonicIndex = lai.getMnemonicIndex();
            // W2K Feature: Check to see if the Underscore should be rendered.
            if (WindowsLookAndFeel.isMnemonicHidden() == true) 
                mnemonicIndex = -1;
            
            if (curLine != lai.getMnemonicLineIndex()) 
                mnemonicIndex = -1;
            
            if (UIManager.getColor("Label.disabledForeground") instanceof Color
                    && UIManager.getColor("Label.disabledShadow") instanceof Color) 
                g.setColor(UIManager.getColor("Label.disabledShadow"));
                BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemonicIndex,
                        textX + 1, textY + 1);
                g.setColor(UIManager.getColor("Label.disabledForeground"));
                BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemonicIndex,
                        textX, textY);
             else 
                Color background = l.getBackground();
                g.setColor(background.brighter());
                BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemonicIndex,
                        textX + 1, textY + 1);
                g.setColor(background.darker());
                BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemonicIndex,
                        textX, textY);
            
        
        @Override
        public void paint(Graphics g, JComponent c) 
            JLabel label = (JLabel) c;
            String text = label.getText();
            Icon icon = (label.isEnabled())
                    ? label.getIcon()
                    : label.getDisabledIcon();

            if ((icon == null) && (text == null)) 
                return;
            
            char mnemonic = (char) label.getDisplayedMnemonic();
            lai.splitText(text, mnemonic);
            List<String> lines = lai.getLines();

            FontMetrics fm = label.getFontMetrics(g.getFont());
            String[] clippedText = new String[lines.size()];
            for (int i = 0; i < lines.size(); i++) 
                clippedText[i] = layout(label, fm, c.getWidth(), c.getHeight(),
                        lines.size(), i, lines.get(i));

                if (icon != null && i == 0) 
                    icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
                

                if (text != null) 
                    int textX = paintTextR.x;
                    int textY = paintTextR.y + fm.getAscent();

                    if (label.isEnabled()) 
                        paintEnabledText(label, g, clippedText[i], textX,
                                textY, i);
                     else 
                        paintDisabledText(label, g, clippedText[i], textX,
                                textY, i);
                    
                
            
        
        @Override
        public int getBaseline(JComponent c, int width, int height) 
            super.getBaseline(c, width, height);
            JLabel label = (JLabel) c;
            String text = label.getText();
            if (text == null || "".equals(text) || label.getFont() == null) 
                return -1;
            
            char mnemonic = (char) label.getDisplayedMnemonic();
            lai.splitText(text, mnemonic);
            List<String> lines = lai.getLines();
            FontMetrics fm = label.getFontMetrics(label.getFont());
            String[] clippedText = new String[lines.size()];
            for (int i = 0; i < lines.size(); i++) 
                clippedText[i] = layout(label, fm, width, height, lines.size(), i,
                        lines.get(i));
            
            return getBaseline(label, paintTextR.y, fm.getAscent(),
                    paintTextR.width, paintTextR.height);
        

        private static class LinesAndIndex 
            private char sep;
            private List<String> lines;
            private int mnemonicLineIndex;
            private int mnemonicIndex;
            LinesAndIndex(char sep) 
                mnemonicLineIndex = -1;
                mnemonicIndex = -1;
                lines = new ArrayList<String>();
                this.sep = sep;
            
            public char getSeparator() 
                return sep;
            
            public void setSeparator(char sep) 
                this.sep = sep;
            
            public List<String> getLines() 
                return lines;
            
            public int getMnemonicLineIndex() 
                return mnemonicLineIndex;
            
            public int getMnemonicIndex() 
                return mnemonicIndex;
            
            public void splitText(String text, char mnemonic) 
                if (text == null) 
                    return;
                
                lines.clear();
                mnemonicLineIndex = -1;
                mnemonicIndex = -1;
                char um = Character.toUpperCase(mnemonic);
                char lm = Character.toLowerCase(mnemonic);
                int umi = Integer.MAX_VALUE;
                int lmi = Integer.MAX_VALUE;
                int umli = -1;
                int lmli = -1;
                for (int i = 0, j = 0, k = 0; i < text.length(); i++) 
                    if (text.charAt(i) == sep) 
                        lines.add(text.substring(j, i));
                        j = i + 1;
                        k++;
                     else if (text.charAt(i) == um) 
                        if (umi == Integer.MAX_VALUE) 
                            umi = i - j;
                            umli = k;
                        
                     else if (text.charAt(i) == lm) 
                        if (lmi == Integer.MAX_VALUE) 
                            lmi = i - j;
                            lmli = k;
                        
                    
                    if (i == text.length() - 1) 
                        lines.add(text.substring(j, i + 1));
                    
                
                mnemonicLineIndex = (lmi < umi) ? lmli : umli;
                mnemonicIndex = (lmi < umi) ? lmi : umi;
            
        

    

【讨论】:

以上是关于如何在不使用 HTML 的情况下向 JLabel 添加换行符的主要内容,如果未能解决你的问题,请参考以下文章

如何在不增加宽度的情况下向文本区域添加填充?

如何在不使用移动网络的情况下向自己发送假短信?

如何让机器人在不使用命令的情况下向特定频道中的特定公会发送消息

如何在不使用 Timer 而是使用 Threads 的情况下实现平滑下降的 JLabel

如何在不覆盖的情况下向 Firebase Firestore 添加值?

如何在不使用 Firebase 控制台的情况下向 iOS 设备发送 Firebase 云消息通知?