在 JScrollPane 内使用 <html> 标签对 JLabel 进行换行 - 删除水平条 functionality/logic

Word wrapping JLabel with <html> tag inside JScrollPane - Remove horizontal bar functionality/logic

我的要求是使用 JLabel.

进行自动换行(就像 JTextArea 那样)

考虑以下代码:

public class WrapTest extends JFrame {

    public WrapTest() {
        super("test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());

        JLabel label = new JLabel("Lorem <b>ipsum</b> dolor sit amet, consectetur adipiscing elit. "
                + "Aliquam non pellentesque enim. Donec nec nisl tortor."
                + " Curabitur rutrum molestie est eget varius. Nullam ut lacinia est."
                + " Phasellus hendrerit sollicitudin justo, vitae malesuada dolor vestibulum at."
                + " Integer pharetra purus sed ipsum pulvinar, et pretium odio volutpat. Donec vitae varius metus."
                + " Cras sagittis vulputate erat, at faucibus lectus faucibus id. Cras varius nunc eu felis tristique dapibus."
                + " Aenean enim eros, dapibus pellentesque nibh ut, efficitur malesuada sapien. Nullam imperdiet nunc velit,"
                + "sed laoreet massa mattis eget. Morbi id justo quis sapien aliquet bibendum sed at leo. In mi felis, consectetur"
                + " sed orci eget, tempus maximus turpis. Curabitur sed felis id nisl vehicula sollicitudin sed eget erat.Ut sagittis at nisi sed facilisis."
                + " Morbi vel felis ac diam molestie consequat. Sed nisl lectus, sollicitudin at neque in, "
                + "placerat aliquet nunc. Maecenas quis enim vitae nunc fermentum congue. Sed posuere quam a ultricies fringilla."
                + " Vivamus aliquam nunc lacus, vitae consectetur tortor consequat ut. Cras viverra mi sit amet magna auctor eleifend."
                + " Morbi in risus nisl. Praesent nunc dolor, lobortis nec ultricies aliquet, sollicitudin eu sapien. Fusce interdum ac leo non suscipit."
                + "Vivamus at viverra elit, ut vestibulum elit. Sed bibendum, lorem et ornare sagittis, erat nulla ultricies odio, quis iaculis lacus nisl "
                + "vel ligula. Sed iaculis elit eu felis consectetur dignissim. ");

        add(label, BorderLayout.CENTER);

        setLocationByPlatform(true);
        setSize(500, 200);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new WrapTest().setVisible(true);
        });
    }
}

文字丑陋且不可读。为了使它更好并添加自动换行,让我们添加 <html> 标签。

String wrap = "<html>";
label.setText(wrap + label.getText());

自动换行是可以的,但是当框架变小时,需要垂直滚动条才能阅读文本。

现在让我们尝试添加一个 JScrollPane 和其中的标签:

String wrap = "<html>";
label.setText(wrap + label.getText());

JScrollPane sp = new JScrollPane(label);
add(sp, BorderLayout.CENTER);

我们有以下结果:

这又使文本不可读。使用 sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 将使滚动条消失,文本保持水平方向。

在这种情况下有没有办法删除单杠的全部功能?我希望标签可以垂直滚动并具有自动换行功能。就像 JTextArea 的行为类似:

我坚持使用 JLabel 的原因是易于渲染 HTML 标签。

我试图通过更改组件的 preferredSize and/or 和 maximumSize 来解决它,但我没有得到想要的结果。我尝试的其他方法是使用 <body style='width:100%'> 或 Xpx,但它们也有其他问题。这是有道理的,当框架变大时,它们不会被调整。

你试过了吗:sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

否则您可以尝试使用支持 HTML 内容的 JEditorPane。然后可以将其放置在 JScrollPane 中。

我相信您可以使用 JEditorPaneJTextArea,您可以禁用编辑并将它们用作容器来显示具有所需换行的文本。

但是如果你坚持使用JLabel的换行和支持垂直滚动,我相信你需要在用户调整框架大小时计算可滚动视口容器的大小:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class WrappedLabel implements Runnable {

    public static void main( String[] args ){
        SwingUtilities.invokeLater( new WrappedLabel() );
    }

    @Override
    public void run(){
        final JPanel panel = new JPanel( new BorderLayout() );

        String text = "Lorem <b>ipsum</b> dolor sit amet, consectetur adipiscing elit. "
                + "Aliquam non pellentesque enim. Donec nec nisl tortor."
                + " Curabitur rutrum molestie est eget varius. Nullam ut lacinia est."
                + " Phasellus hendrerit sollicitudin justo, vitae malesuada dolor vestibulum at."
                + " Integer pharetra purus sed ipsum pulvinar, et pretium odio volutpat. Donec vitae varius metus."
                + " Cras sagittis vulputate erat, at faucibus lectus faucibus id. Cras varius nunc eu felis tristique dapibus."
                + " Aenean enim eros, dapibus pellentesque nibh ut, efficitur malesuada sapien. Nullam imperdiet nunc velit,"
                + "sed laoreet massa mattis eget. Morbi id justo quis sapien aliquet bibendum sed at leo. In mi felis, consectetur"
                + " sed orci eget, tempus maximus turpis. Curabitur sed felis id nisl vehicula sollicitudin sed eget erat.Ut sagittis at nisi sed facilisis."
                + " Morbi vel felis ac diam molestie consequat. Sed nisl lectus, sollicitudin at neque in, "
                + "placerat aliquet nunc. Maecenas quis enim vitae nunc fermentum congue. Sed posuere quam a ultricies fringilla."
                + " Vivamus aliquam nunc lacus, vitae consectetur tortor consequat ut. Cras viverra mi sit amet magna auctor eleifend."
                + " Morbi in risus nisl. Praesent nunc dolor, lobortis nec ultricies aliquet, sollicitudin eu sapien. Fusce interdum ac leo non suscipit."
                + "Vivamus at viverra elit, ut vestibulum elit. Sed bibendum, lorem et ornare sagittis, erat nulla ultricies odio, quis iaculis lacus nisl "
                + "vel ligula. Sed iaculis elit eu felis consectetur dignissim. ";
        JLabel label = new JLabel("<html>" +text+ "</html>");
        panel.add( label, BorderLayout.CENTER );

        final JFrame frame = new JFrame();
        frame.add( new WrappingScrollPane( panel ) );
        frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
        frame.setSize( 256, 256 );
        frame.setVisible( true );
    }
}

class WrappingScrollPane extends JScrollPane implements ComponentListener {

    WrappingScrollPane( Container view ){
        super( view );
        this.viewport.addComponentListener( this );
    }

    @Override
    public void componentHidden( ComponentEvent ce ){
    }

    @Override
    public void componentMoved( ComponentEvent ce ){
    }

    /** calculating required height is a 3 step process
      * 1. sync width of client and viewport, set height of client to high value
      * 2. let LayoutManager calculate required minimum size
      * 3. set preferredSize and revalidate
     **/
    @Override
    public void componentResized( ComponentEvent ce ){
        final Container view = (Container) this.viewport.getView();
        final int width = this.viewport.getExtentSize().width;
        view.setPreferredSize( new Dimension( width, Integer.MAX_VALUE ) );
        final int height = view.getLayout().preferredLayoutSize( view ).height;
        view.setPreferredSize( new Dimension( width, height ) );
        view.revalidate();
    }

    @Override
    public void componentShown( ComponentEvent ce ){
    }
}

您需要做的是在添加到滚动窗格的组件上实现 Scrollable 接口。

然后你可以强制组件适应视口的宽度。

最简单的方法是使用 Scrollable Panel,它实现了 Scrollable 接口的方法并允许您自定义行为。

然后将标签添加到 ScrollablePanel 并将面板添加到滚动窗格:

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


public class WrapTest extends JFrame {

    public WrapTest() {
        super("test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());

        JLabel label = new JLabel("<html>Lorem <b>ipsum</b> dolor sit amet, consectetur adipiscing elit. "
                + "Aliquam non pellentesque enim. Donec nec nisl tortor."
                + " Curabitur rutrum molestie est eget varius. Nullam ut lacinia est."
                + " Phasellus hendrerit sollicitudin justo, vitae malesuada dolor vestibulum at."
                + " Integer pharetra purus sed ipsum pulvinar, et pretium odio volutpat. Donec vitae varius metus."
                + " Cras sagittis vulputate erat, at faucibus lectus faucibus id. Cras varius nunc eu felis tristique dapibus."
                + " Aenean enim eros, dapibus pellentesque nibh ut, efficitur malesuada sapien. Nullam imperdiet nunc velit,"
                + "sed laoreet massa mattis eget. Morbi id justo quis sapien aliquet bibendum sed at leo. In mi felis, consectetur"
                + " sed orci eget, tempus maximus turpis. Curabitur sed felis id nisl vehicula sollicitudin sed eget erat.Ut sagittis at nisi sed facilisis."
                + " Morbi vel felis ac diam molestie consequat. Sed nisl lectus, sollicitudin at neque in, "
                + "placerat aliquet nunc. Maecenas quis enim vitae nunc fermentum congue. Sed posuere quam a ultricies fringilla."
                + " Vivamus aliquam nunc lacus, vitae consectetur tortor consequat ut. Cras viverra mi sit amet magna auctor eleifend."
                + " Morbi in risus nisl. Praesent nunc dolor, lobortis nec ultricies aliquet, sollicitudin eu sapien. Fusce interdum ac leo non suscipit."
                + "Vivamus at viverra elit, ut vestibulum elit. Sed bibendum, lorem et ornare sagittis, erat nulla ultricies odio, quis iaculis lacus nisl "
                + "vel ligula. Sed iaculis elit eu felis consectetur dignissim. ");


        ScrollablePanel panel = new ScrollablePanel( new BorderLayout() );
        panel.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
        panel.add( label );

        JScrollPane sp = new JScrollPane(panel);
        add(sp, BorderLayout.CENTER);

        setLocationByPlatform(true);
        setSize(500, 200);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new WrapTest().setVisible(true);
        });
    }
}