带有换行符的JTextArea向JDialog Pack报告了不正确的首选大小?

问题描述 投票:0回答:1

我正在使用多个JTextAreas显示大小可变的文本,其中LineWrap和WrapStyleWord均为true。一个应用程序是在JScrollPane中显示一个JDialog,其中包含多个文本区域。包含所有这些文本区域的面板实现Scrollable(如here所述),从而允许JDialog具有最大大小,但仍会缩小。但是,JDialog具有设置的水平大小。除非对话框达到其最大大小,否则将强制水平滚动条从不显示,并且垂直滚动条不应显示。但是,在JTextArea换行的情况下,当JDialog的高度小于其最大值时,将显示垂直滚动条。问题似乎是在打包JDialog时,JTextArea报告了一行的首选高度,这导致对话框的高度小于面板的高度,因为文本区域占据了一行以上。

这似乎是一个catch-22,因为要获得适当的文本区域高度,需要将其添加到具有所需宽度的面板中以计算换行,这将允许对实际行进行计数(使用方法here)。但是在调用pack之前,JDialog需要一个首选大小(据我的理解),从而导致了问题。演示问题:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Scrollable;

public class DisplayPopup extends JDialog {

    public DisplayPopup() {

        JPanel actual = new JPanel(); 
        actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
        actual.setOpaque(false);

        JTextArea jta = new JTextArea();
        jta.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ac dictum magna. Nam sed mattis sem. Donec tortor felis, finibus in lectus fringilla, semper finibus turpis. ");
        jta.setFont(new java.awt.Font("Arial", 0, 18));
        jta.setForeground(new java.awt.Color(204, 204, 204));
        jta.setLineWrap(true);
        jta.setWrapStyleWord(true);
        jta.setEditable(false);
        jta.setBackground(new Color(45,45,45));
        jta.setHighlighter(null);
        actual.add(jta);

        PopupScroll ps = new PopupScroll(actual);

        JScrollPane scroll = new JScrollPane(); 
        scroll.getViewport().add(ps);

        setModalityType(java.awt.Dialog.ModalityType.MODELESS);
        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setResizable(false);
        setLocationRelativeTo(null);
        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(scroll);

        pack();
    }

    public static void launch() {
        DisplayPopup dp = new DisplayPopup();
        dp.setVisible(true);
    }

    public static void main(String[] args) {                                                    
        javax.swing.SwingUtilities.invokeLater(DisplayPopup::launch);                                                                                       
    } 

    private class PopupScroll extends JPanel implements Scrollable {

        public PopupScroll(JPanel jp) {
            setBackground(Color.PINK);
            setLayout(new BorderLayout());
            add(jp);
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            return new Dimension(500,Math.min((int)getPreferredSize().getHeight(),700));
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle arg0, int arg1, int arg2) {
            return 1;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle arg0, int arg1, int arg2) {
            return 1;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            return true; 
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            return false;
        }

    }

}

对话框的大小不能包含所有文本行。与this解决类似问题的方法不同,调用包不能解决问题。我对解决方案有一些猜测,也许使用了JTextArea之外的其他东西(因为我只想显示文本...?),但是我不知道那是什么。我尝试将层次结构侦听器放在垂直滚动条上,以便在不显示对话框的情况下可以检测到它何时处于活动状态,但这是行不通的。这是一个难题吗,还是我遗漏了一些明显的东西?

java swing awt jtextarea jdialog
1个回答
0
投票

进行了几处更改,我看到显示在三行上的文本:

pack();
pack();

是的,我添加了第二个pack()。第一个包似乎可以识别宽度,第二个包可以使文本被换行。

但是,我还必须更改:

//actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
actual.setLayout(new BorderLayout());

我知道您实际上并不想使用BorderLayout(因为您希望多个组件垂直对齐),但是以某种方式,它似乎更喜欢使用大小计算。

代替BoxLayout,您可能可以使用GridBagLayout。它允许您指定“填充”约束。我想您会只尝试水平填充。

或者另一个选择是使用Relative Layout。我将比GridBagLayout容易,因为您无需担心任何约束。使用它的代码将是:

//actual.setLayout(new BoxLayout(actual, BoxLayout.Y_AXIS));
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
actual.setLayout( rl );
© www.soinside.com 2019 - 2024. All rights reserved.