简体   繁体   English

添加填充有文本的 JTextArea/JTextPane 时防止 JSscrollPane 调整大小

[英]Prevent JSscrollPane from resizing when adding JTextArea/JTextPane populated with text

Hello people on the internet你好互联网上的人们

My problem is that when I call setViewPortView(textArea) on the JScrollPane with the JTextArea already having text in it, the JScrollPane resizes to fit the entire text of the JTextArea .我的问题是,当我在JScrollPane上调用setViewPortView(textArea)并且JTextArea中已经包含文本时, JScrollPane会调整大小以适应JTextArea的整个文本。 I would rather want the scroll pane to remain the same size while having the rest of the text hidden in the scroll pane below, so that I can scroll down to see the rest of the text.我希望滚动窗格保持相同的大小,同时将文本的 rest 隐藏在下面的滚动窗格中,以便我可以向下滚动以查看文本的 rest。

See the below example that should be ready to run:请参阅下面应该可以运行的示例:

  1. Click on the "Edit" button.单击“编辑”按钮。 The JTextPane is now replaced with a JTextArea which is editable. JTextPane现在替换为可编辑的JTextArea
  2. Type into the JTextArea above the button.在按钮上方的JTextArea中键入。 Type enough text so that it starts to scroll down as it's supposed to, many lines of text.键入足够多的文本,使其开始按预期向下滚动,多行文本。
  3. Click the same button again which is now titled "Save".再次单击现在标题为“保存”的相同按钮。 Now a non editable JTextPane will be displayed in the JScrollPane instead of the JTextArea .现在,一个不可编辑的JTextPane将显示在JScrollPane而不是JTextArea中。
  4. See how the JSCrollPane resized?看看JSCrollPane是如何调整大小的?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main extends JFrame {
    private final JScrollPane scrollPane;
    private final JTextArea textArea;
    private final JTextPane textPane;
    private final JButton editButton;
    private String text;

    private boolean isEditing = false;


    public Main() {
        setLayout(new GridBagLayout());
        textArea = new JTextArea();
        textArea.setVisible(false);
        textPane = new JTextPane();
        textPane.setEditable(false);
        scrollPane = new JScrollPane();
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setViewportView(textPane);
        editButton = new JButton("Edit");
        editButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                isEditing = !isEditing;
                textPane.setVisible(!isEditing);
                textArea.setVisible(isEditing);
                if(isEditing) {
                    scrollPane.setViewportView(textArea);
                    editButton.setText("Save");
                }
                else {
                    scrollPane.setViewportView(textPane);
                    editButton.setText("Edit");
                    text = textArea.getText();
                }
                textPane.setText(text);
            }
        });

        GridBagConstraints bag = new GridBagConstraints();
        bag.gridx = 0;
        bag.gridy = 0;
        bag.gridwidth = 3;
        bag.gridheight = 1;
        bag.weightx = 1.0;
        bag.weighty = 1.0;
        bag.fill = GridBagConstraints.BOTH;
        bag.anchor = GridBagConstraints.NORTH;
        bag.insets = new Insets(5, 5, 0, 5);
        add(scrollPane, bag);

        bag = new GridBagConstraints();
        bag.gridx = 1;
        bag.gridy = 1;
        bag.gridwidth = 1;
        bag.gridheight = 1;
        bag.weightx = 1.0;
        bag.weighty = 1.0;
        add(editButton, bag);

        setSize(1000, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Main ui = new Main();
        });
    }
}

PS: I am swapping to a JTextPane because I am planning to render markdown text which I have excluded to keep the example simple. PS:我正在切换到JTextPane ,因为我计划渲染 markdown 文本,我已将其排除在外以保持示例简单。 I am using JDK 8u231我正在使用 JDK 8u231

I have tried saving the original size and setting it using setPreferredSize and setMaximumSize when I swap them out but it did not solve my problem.我尝试保存原始大小并在将它们换出时使用setPreferredSizesetMaximumSize进行设置,但这并没有解决我的问题。 I would also like to keep it resizable for when the window resizes.我还想在 window 调整大小时保持它的大小。

Update: I need to use the GridBag layout because I have a JPanel on which I draw by overriding the paint() function just above it更新:我需要使用GridBag布局,因为我有一个JPanel ,我通过覆盖它上面的paint() function 在其上绘制

Swing components should determine their own preferred size. Swing 组件应确定自己的首选尺寸。 You should NOT be hardcoding random sizes.您不应该对随机大小进行硬编码。 Then the layout manager can use this information.然后布局管理器可以使用此信息。

The easiest way to do this is to give a hint to the JTextArea for the number of rows/columns it should contain by using:最简单的方法是使用以下命令向 JTextArea 提示它应该包含的行/列数:

JTextArea textArea = new JTextArea(15, 40);

You then use the appropriate layout manager to allow the components to dynamically resize as the frame size changes.然后,您可以使用适当的布局管理器来允许组件随着框架大小的变化而动态调整大小。 I would use the BorderLayout for this.我会为此使用 BorderLayout。 Then after you add the components to the frame you pack the frame.然后在您将组件添加到框架后,您可以打包框架。

A basic solution might be:一个基本的解决方案可能是:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main5 extends JFrame {
    private final JScrollPane scrollPane;
    private final JTextArea textArea;
    private final JTextPane textPane;
    private final JButton editButton;
    private String text;

    private boolean isEditing = false;


    public Main5() {
//        setLayout(new GridBagLayout());
//        textArea = new JTextArea();
//       textArea.setVisible(false);
        setLayout( new BorderLayout() );
        textArea = new JTextArea(15, 40);
        textPane = new JTextPane();
        textPane.setPreferredSize( textArea.getPreferredSize() );
        textPane.setEditable(false);
        scrollPane = new JScrollPane();
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setViewportView(textPane);

        editButton = new JButton("Edit");
        editButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                isEditing = !isEditing;
                textPane.setVisible(!isEditing);
//                textArea.setVisible(isEditing);
                if(isEditing) {
                    scrollPane.setViewportView(textArea);
                    editButton.setText("Save");
                    textArea.requestFocusInWindow();
                }
                else {
                    scrollPane.setViewportView(textPane);
                    editButton.setText("Edit");
                    text = textArea.getText();
                }
                textPane.setText(text);
            }
        });
/*
        GridBagConstraints bag = new GridBagConstraints();
        bag.gridx = 0;
        bag.gridy = 0;
        bag.gridwidth = 3;
        bag.gridheight = 1;
        bag.weightx = 1.0;
        bag.weighty = 1.0;
        bag.fill = GridBagConstraints.BOTH;
        bag.anchor = GridBagConstraints.NORTH;
        bag.insets = new Insets(5, 5, 0, 5);
        add(scrollPane, bag);

        bag = new GridBagConstraints();
        bag.gridx = 1;
        bag.gridy = 1;
        bag.gridwidth = 1;
        bag.gridheight = 1;
        bag.weightx = 1.0;
        bag.weighty = 1.0;
        add(editButton, bag);
*/
        add(scrollPane, BorderLayout.CENTER);

        JPanel wrapper = new JPanel();
        wrapper.add(editButton);
        add(wrapper, BorderLayout.PAGE_END);

//        setSize(1000, 500);
        pack();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Main5 ui = new Main5();
        });
    }
}

Even if you convert this to use a CardLayout it will still work because the size of the card panel is determined by the size of the largest panel added to it.即使您将其转换为使用 CardLayout 它仍然可以工作,因为卡片面板的大小由添加到其中的最大面板的大小决定。

Ok I have found a solution.好的,我找到了解决方案。 If I set the preferred size of the JScrollPane to some fixed value that is not too large then it still remains the size I want it to be and it doesn't grow vertically.如果我将JScrollPane的首选大小设置为某个不太大的固定值,那么它仍然保持我想要的大小并且它不会垂直增长。 It also resizes with the window when I resize the window.当我调整 window 的大小时,它也会用 window 调整大小。 See the code below and thank you to Andrew Thompson in the comments for suggesting a CardLayout .请参阅下面的代码,并感谢 Andrew Thompson 在评论中提出CardLayout的建议。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main extends JFrame {
    private final JScrollPane scrollPane;
    private final JTextArea textArea;
    private final JTextPane textPane;
    private final JButton editButton;
    private String text;
    private final JPanel cardPanel;
    private final CardLayout cards;

    private boolean isEditing = false;
    
    public Main() {
        setLayout(new GridBagLayout());
        textArea = new JTextArea();
        textPane = new JTextPane();
        textPane.setEditable(false);
        cards = new CardLayout();
        cardPanel = new JPanel();
        cardPanel.setLayout(cards);
        cardPanel.add(textPane);
        cardPanel.add(textArea);
        scrollPane = new JScrollPane(cardPanel);
        scrollPane.setPreferredSize(new Dimension(Integer.MAX_VALUE, 50));
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        editButton = new JButton("Edit");
        editButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                isEditing = !isEditing;
                if(isEditing) {
                    editButton.setText("Save");
                }
                else {
                    editButton.setText("Edit");
                    text = textArea.getText();
                }
                textPane.setText(text);
                cards.next(cardPanel);
            }
        });

        GridBagConstraints bag = new GridBagConstraints();
        bag.gridx = 0;
        bag.gridy = 0;
        bag.gridwidth = 3;
        bag.gridheight = 1;
        bag.weightx = 1.0;
        bag.weighty = 1.0;
        bag.fill = GridBagConstraints.BOTH;
        bag.anchor = GridBagConstraints.NORTH;
        bag.insets = new Insets(5, 5, 0, 5);
        add(scrollPane, bag);

        bag = new GridBagConstraints();
        bag.gridx = 1;
        bag.gridy = 1;
        bag.gridwidth = 1;
        bag.gridheight = 1;
        bag.weightx = 1.0;
        bag.weighty = 1.0;
        add(editButton, bag);

        setSize(1000, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Main ui = new Main();
        });
    }
}

I have added: scrollPane.setPreferredSize(new Dimension(Integer.MAX_VALUE, 50));我添加了: scrollPane.setPreferredSize(new Dimension(Integer.MAX_VALUE, 50));

I don't actually want it to be 50 but fortunately it doesn't make it 50 pixels high.我实际上并不希望它为 50,但幸运的是它并没有使其高 50 像素。 I just wanted it to stay more or less half the height of the window as it was in the beginning.我只是希望它保持在开始时 window 高度的一半左右。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM