Java 是否使用Swing布局管理器/解决方案替换动态创建和嵌套的拆分窗格?
我正在开发一个文本编辑器,在这个编辑器中,用户可以自由地将编辑器窗口垂直或水平划分任意次数(即,划分为任意数量的窗格)。单个窗口可以垂直和水平划分(例如,两行,一行包含3列,等等)。每个窗格都包含一个JScrollPane内的JTextArea和一个状态栏 到目前为止,我的方法是使用嵌套的JSplitPanes。我一直在努力安排拆分窗格分隔符,以便窗口中的空间在所有垂直或水平拆分窗格中平均分配。我已经非常接近正确,但我不得不在许多地方()使用setPreferredSize() 我想知道采取完全不同的方法是否更容易/更好。看起来很诱人Java 是否使用Swing布局管理器/解决方案替换动态创建和嵌套的拆分窗格?,java,swing,layout-manager,jxmultisplitpane,multisplitpane,Java,Swing,Layout Manager,Jxmultisplitpane,Multisplitpane,我正在开发一个文本编辑器,在这个编辑器中,用户可以自由地将编辑器窗口垂直或水平划分任意次数(即,划分为任意数量的窗格)。单个窗口可以垂直和水平划分(例如,两行,一行包含3列,等等)。每个窗格都包含一个JScrollPane内的JTextArea和一个状态栏 到目前为止,我的方法是使用嵌套的JSplitPanes。我一直在努力安排拆分窗格分隔符,以便窗口中的空间在所有垂直或水平拆分窗格中平均分配。我已经非常接近正确,但我不得不在许多地方()使用setPreferredSize() 我想知道采取完全
对于我的情况,什么样的布局/方法是最好的?现在我正在对你想要什么做一些假设。我想你会问,是否有一种简单的方法可以动态添加宽度/高度都相同的文本窗格(垂直或水平拆分,但不要将两者混合) 水平拆分示例 垂直拆分示例 如果是这样的话,我建议使用BoxLayout——它几乎不需要任何配置就可以做到这一点
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SplitablePanel extends Box{
Box container;
Dimension minSize = new Dimension(400, 300);
public SplitablePanel(int axis){
super(BoxLayout.Y_AXIS);
//Container that holds all the text areas
container = new Box(axis);
container.setAlignmentX(Box.LEFT_ALIGNMENT);
add(container);
JTextArea text = new JTextArea();
container.add(new JScrollPane(text));
//Button to add another pane
JButton split = new JButton("Split");
split.setAlignmentX(Box.LEFT_ALIGNMENT);
split.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
JTextArea text = new JTextArea();
container.add(new JScrollPane(text));
revalidate();
}});
add(split);
//Button To switch Axis - more for demo purposes
JButton axisChanger = new JButton("Change Axis");
axisChanger.setAlignmentX(Box.LEFT_ALIGNMENT);
axisChanger.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Box newContainer;
if(((BoxLayout)container.getLayout()).getAxis() == BoxLayout.X_AXIS){
newContainer = Box.createVerticalBox();
} else{
newContainer = Box.createHorizontalBox();
}
for(Component c : container.getComponents()){
container.remove(c);
newContainer.add(c);
}
remove(container);
add(newContainer, 0);
container = newContainer;
container.setAlignmentX(Box.LEFT_ALIGNMENT);
revalidate();
}
});
add(axisChanger);
}
@Override
public Dimension getPreferredSize() {
Dimension result = super.getPreferredSize();
result.width = result.width > minSize.width ? result.width : minSize.width;
result.height = result.height > minSize.height ? result.height : minSize.height;
return result;
}
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SplitablePanel(BoxLayout.X_AXIS));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
我决定花一些时间学习Multiplitpane布局。这看起来是一个很好的解决方案 下面是我作为测试编写的代码。它本质上是对布局的模拟,当用户以各种方式拆分窗口时,布局会动态变化。这有点长,但可能对试图学习MultiplitPane的人有帮助 最终结果如下所示:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.util.LinkedList;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import org.jdesktop.swingx.MultiSplitPane;
import org.jdesktop.swingx.MultiSplitLayout.*;
@SuppressWarnings("serial")
class MultiSplitPaneTest extends JFrame {
private final static String sampleText;
static {
String text = "I'm working on a text editor in which the user is free to divide the editor window vertically or horizontally any number of times (ie, into any number of panes).\n";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append(text);
}
sampleText = sb.toString();
}
private class MyScrollPane extends JScrollPane {
public MyScrollPane(final Component view) {
super(view);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(1440, 900);
}
}
public MultiSplitPaneTest() {
// The application opens with a window containing a single pane (a single text area).
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JTextArea ta1 = new JTextArea();
ta1.setText("TEXT AREA 1\n" + sampleText);
MyScrollPane sp1 = new MyScrollPane(ta1);
sp1.setViewportView(ta1);
cp.add(sp1, BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
// -------------------------------------------------
// Let's say the user splits the window horizontally, creating a second pane.
// We'll simulate that with the following code.
JTextArea ta2 = new JTextArea();
ta2.setText("TEXT AREA 2\n" + sampleText);
MyScrollPane sp2 = new MyScrollPane(ta2);
sp2.setViewportView(ta2);
Leaf leaf1 = new Leaf("1");
Leaf leaf2 = new Leaf("2");
LinkedList<Node> rootChildren = new LinkedList<>();
rootChildren.add(leaf1);
rootChildren.add(new Divider());
rootChildren.add(leaf2);
Split root = new Split();
root.setRowLayout(true);
root.setChildren(rootChildren);
MultiSplitPane multiSplitPane = new MultiSplitPane();
multiSplitPane.getMultiSplitLayout().setModel(root);
multiSplitPane.add(sp1, "1");
multiSplitPane.add(sp2, "2");
cp.remove(sp1);
cp.add(multiSplitPane, BorderLayout.CENTER);
// --------------------------------------------------
// Let's say the user splits the window horizontally again, creating a new pane on the very left.
JTextArea ta3 = new JTextArea();
ta3.setText("TEXT AREA 3\n" + sampleText);
MyScrollPane sp3 = new MyScrollPane(ta3);
sp3.setViewportView(ta3);
Leaf leaf3 = new Leaf("3");
rootChildren.add(0, leaf3);
rootChildren.add(1, new Divider());
root.setChildren(rootChildren);
multiSplitPane.add(sp3, "3");
multiSplitPane.revalidate();
// --------------------------------------------------
// Let's say the user decides to remove the center pane (that is, the first pane that we started with).
rootChildren.remove(2); // Remove leaf1.
rootChildren.remove(2); // Remove the divider following leaf1.
root.setChildren(rootChildren);
multiSplitPane.remove(sp1);
multiSplitPane.revalidate();
// --------------------------------------------------
// Let's say the user creates another pane, this time splitting the pane on the right vertically.
rootChildren.remove(leaf2);
JTextArea ta4 = new JTextArea();
ta4.setText("TEXT AREA 4\n" + sampleText);
MyScrollPane sp4 = new MyScrollPane(ta4);
sp4.setViewportView(ta4);
Leaf leaf4 = new Leaf("4");
LinkedList<Node> branchChildren = new LinkedList<>();
branchChildren.add(leaf2);
branchChildren.add(new Divider());
branchChildren.add(leaf4);
Split branch = new Split();
branch.setRowLayout(false);
branch.setChildren(branchChildren);
rootChildren.add(branch);
root.setChildren(rootChildren);
multiSplitPane.add(sp4, "4");
multiSplitPane.revalidate();
}
}
导入java.awt.BorderLayout;
导入java.awt.Component;
导入java.awt.Container;
导入java.awt.Dimension;
导入java.util.LinkedList;
导入javax.swing.JFrame;
导入javax.swing.JScrollPane;
导入javax.swing.JTextArea;
导入org.jdesktop.swingx.multiplitpane;
导入org.jdesktop.swingx.multiplitlayout.*;
@抑制警告(“串行”)
类multiplitpanetest扩展了JFrame{
私有最终静态字符串sampleText;
静止的{
String text=“我正在使用一个文本编辑器,在该编辑器中,用户可以自由地垂直或水平分割编辑器窗口任意次数(即,分割成任意数量的窗格)。\n”;
StringBuilder sb=新的StringBuilder();
对于(int i=0;i<10;i++){
附加(正文);
}
sampleText=sb.toString();
}
私有类MyScrollPane扩展了JScrollPane{
公共MyScrollPane(最终组件视图){
超级(视图);
}
@凌驾
公共维度getPreferredSize(){
返回新尺寸(1440900);
}
}
公共多重分裂网络测试(){
//应用程序将打开一个包含单个窗格(单个文本区域)的窗口。
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
容器cp=getContentPane();
cp.setLayout(新的BorderLayout());
JTextArea ta1=新的JTextArea();
ta1.setText(“文本区域1\n”+样本文本);
MyScrollPane sp1=新的MyScrollPane(ta1);
sp1.setViewportView(ta1);
cp.add(sp1,BorderLayout.CENTER);
包装();
setLocationRelativeTo(空);
setVisible(真);
// -------------------------------------------------
//假设用户水平拆分窗口,创建第二个窗格。
//我们将用下面的代码来模拟它。
JTextArea ta2=新的JTextArea();
ta2.setText(“文本区域2\n”+样本文本);
MyScrollPane sp2=新的MyScrollPane(ta2);
sp2.setViewportView(ta2);
叶1=新叶(“1”);
叶2=新叶(“2”);
LinkedList rootChildren=新建LinkedList();
rootChildren.add(leaf1);
添加(新的分隔符());
rootChildren.add(leaf2);
拆分根=新拆分();
root.setRowLayout(true);
root.setChildren(rootChildren);
MultiplitPane MultiplitPane=新的MultiplitPane();
multiplitpane.getmultiplitlayout().setModel(根);
multiplitpane.add(sp1,“1”);
MultiplitPane.add(sp2,“2”);
cp.remove(sp1);
cp.add(MultiplitPane,BorderLayout.CENTER);
// --------------------------------------------------
//假设用户再次水平拆分窗口,在最左侧创建一个新窗格。
JTextArea ta3=新的JTextArea();
ta3.setText(“文本区域3\n”+样本文本);
MyScrollPane sp3=新的MyScrollPane(ta3);
sp3.setViewportView(ta3);
叶3=新叶(“3”);
添加(0,3);
添加(1,新分隔符());
root.setChildren(rootChildren);
MultiplitPane.add(sp3,“3”);
multiplitpane.revalidate();
// --------------------------------------------------
//假设用户决定删除中心窗格(即我们开始使用的第一个窗格)。
rootChildren.remove(2);//删除leaf1。
rootChildren.remove(2);//删除leaf1后面的分隔符。
root.setChildren(rootChildren);
多平面。移除(sp1);
multiplitpane.revalidate();
// --------------------------------------------------
//假设用户创建了另一个窗格,这次垂直拆分右侧的窗格。
去根(叶2);
JTextArea ta4=新的JTextArea();
ta4.setText(“文本区域4\n”+样本文本);
MyScrollPane sp4=新的MyScrollPane(ta4);
sp4.setViewportView(ta4);
叶4=新叶(“4”);
LinkedList branchChildren=新LinkedList();
添加(叶2);
添加(新的分隔符());
添加(叶4);