添加用文本填充的JTextArea/JTextPane时,阻止JSscrollPane调整大小



大家好,

我的问题是,当我在JScrollPane上调用setViewPortView(textArea),而JTextArea中已经有文本时,JScrollPane会调整大小以适应JTextArea的整个文本。我希望滚动窗格保持不变,同时将其余文本隐藏在下面的滚动窗格中,这样我就可以向下滚动查看其余文本。

请参阅下面应该准备运行的示例:

  1. 点击";编辑";按钮JTextPane现在替换为可编辑的JTextArea
  2. 在按钮上方的JTextArea中键入。键入足够的文本,使其开始按预期向下滚动,包括多行文本
  3. 再次点击相同的按钮,现在标题为";保存";。现在,不可编辑的JTextPane将显示在JScrollPane中,而不是JTextArea
  4. 查看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();
});
}
}

附言:我要换成JTextPane,因为我计划呈现标记文本,为了保持示例的简单性,我已经排除了这些文本。我正在使用JDK 8u231

我尝试过保存原始大小,并在交换它们时使用setPreferredSizesetMaximumSize进行设置,但这并没有解决我的问题。我还想在窗口调整大小时保持它的大小可调。

更新:我需要使用GridBag布局,因为我有一个JPanel,我通过覆盖上方的paint()函数来绘制它

Swing组件应该确定自己喜欢的大小。你不应该硬编码随机大小。然后布局管理器可以使用这些信息。

最简单的方法是使用向JTextArea提示它应该包含的行/列数

JTextArea textArea = new JTextArea(15, 40);

然后,您可以使用适当的布局管理器来允许组件随着框架大小的更改而动态调整大小。我会使用BorderLayout。然后,在将零部件添加到框架后,即可对框架进行打包。

一个基本的解决方案可能是:

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();
});
}
}

即使您将其转换为使用CardLayout,它仍然可以工作,因为插卡面板的大小由添加到其中的最大面板的大小决定。

好的,我找到了解决方案。如果我将JScrollPane的首选大小设置为某个不太大的固定值,那么它仍然保持我希望的大小,并且不会垂直增长。当我调整窗口大小时,它也会随窗口调整大小。请参阅下面的代码,并感谢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();
});
}
}

我补充道:scrollPane.setPreferredSize(new Dimension(Integer.MAX_VALUE, 50));

我其实并不希望它是50,但幸运的是,它没有使它达到50像素高。我只是想让它保持在窗户高度的一半左右。

最新更新