如果用户移动了分隔符的位置,如何让JSplitPane保持相同的比例位置

在调整容器大小时,我无法让JSplitPane保持相同的相对位置。 如果假设拆分窗格具有固定位置,则一切正常。 我可以使用下面显示的代码使分隔符位置保持接近相同的相对位置,但是在调整JFrame大小时分隔符向左移动。 如果JFrame缓慢resize,则移位更大。 如果JFrame变小或变大,则向左移动。

如何让分频器保持在完全相同的比例位置?

这就是GUI最初的样子。

在此处输入图像描述

这是几次调整后的样子。
在此处输入图像描述

这就是代码的样子。 此尝试基于此处提供的信息:

JSplitPane精确分裂50%

JSplitPane SetDividerLocation问题

https://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html

import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSplitPane; public class Example { public static void main(String[] args) { new Example().showGui(); } private void showGui() { // create the jframe JFrame jFrame = new JFrame(); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setSize(400, 200); // create the left and right panels JPanel left = new JPanel(); left.setBackground(Color.yellow); JPanel right = new JPanel(); right.setBackground(Color.orange); ResizableSplitPane split = new ResizableSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right, jFrame); jFrame.getContentPane().add(split); // show the gui jFrame.setVisible(true); } public class ResizableSplitPane extends JSplitPane { // // instance variables // private boolean painted; private double defaultDividerLocation; private ResizableSplitPane resizableSplitPane = this; private double currentDividerLocation; private Component first; private Component second; private boolean dividerPositionCaptured = false; // // constructors // public ResizableSplitPane(int splitType, Component first, Component second, Component parent) { this(splitType, first, second, parent, 0.5); } public ResizableSplitPane(int splitType, Component first, Component second, Component parent, double defaultDividerLocation) { super(splitType, first, second); this.defaultDividerLocation = defaultDividerLocation; this.currentDividerLocation = defaultDividerLocation; this.setResizeWeight(defaultDividerLocation); this.first = first; this.second = second; parent.addComponentListener(new DividerLocator()); first.addComponentListener(new DividerMovedByUserComponentAdapter()); } // // trivial getters and setters // public double getDefaultDividerLocation() { return defaultDividerLocation; } public void setDefaultDividerLocation(double defaultDividerLocation) { this.defaultDividerLocation = defaultDividerLocation; } // // implementation // @Override public void paint(Graphics g) { super.paint(g); if (!painted) { painted = true; this.setDividerLocation(currentDividerLocation); } dividerPositionCaptured = false; } private class DividerLocator extends ComponentAdapter { @Override public void componentResized(ComponentEvent e) { setDividerLocation(currentDividerLocation); } } private class DividerMovedByUserComponentAdapter extends ComponentAdapter { @Override public void componentResized(ComponentEvent e) { if (dividerPositionCaptured == false) { dividerPositionCaptured = true; currentDividerLocation = (double) first.getWidth() / (double) (first.getWidth() + second.getWidth()); System.out.println(currentDividerLocation); } } } } } 

  • 这是我的尝试:
    • 在完成JSplitPane的大小调整后,覆盖JSplitPane的父组件的doLayout方法,以调整分隔符的位置。
 import java.awt.*; import java.awt.event.*; import java.math.BigDecimal; import javax.swing.*; public class Example2 { public static void main(String[] args) { EventQueue.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new Example2().makeUI()); f.setSize(400, 240); f.setLocationRelativeTo(null); f.setVisible(true); }); } private JComponent makeUI() { JPanel p = new JPanel(new GridLayout(0, 1, 0, 0)); JPanel left1 = new JPanel(); left1.setBackground(Color.YELLOW); JPanel right1 = new JPanel(); right1.setBackground(Color.ORANGE); JSplitPane split1 = new ResizableSplitPane( JSplitPane.HORIZONTAL_SPLIT, left1, right1, p); p.add(split1); JPanel left2 = new JPanel(); left2.setBackground(Color.YELLOW); JPanel right2 = new JPanel(); right2.setBackground(Color.ORANGE); JSplitPane split2 = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, left2, right2); p.add(new SplitPaneWrapper(split2)); return p; } } class ResizableSplitPane extends JSplitPane { // // instance variables // private boolean painted; private double defaultDividerLocation; private ResizableSplitPane resizableSplitPane = this; private double currentDividerLocation; private Component first; private Component second; private boolean dividerPositionCaptured = false; // // constructors // public ResizableSplitPane(int splitType, Component first, Component second, Component parent) { this(splitType, first, second, parent, 0.5); } public ResizableSplitPane(int splitType, Component first, Component second, Component parent, double defaultDividerLocation) { super(splitType, first, second); this.defaultDividerLocation = defaultDividerLocation; this.currentDividerLocation = defaultDividerLocation; this.setResizeWeight(defaultDividerLocation); this.first = first; this.second = second; parent.addComponentListener(new DividerLocator()); first.addComponentListener(new DividerMovedByUserComponentAdapter()); } // // trivial getters and setters // public double getDefaultDividerLocation() { return defaultDividerLocation; } public void setDefaultDividerLocation(double defaultDividerLocation) { this.defaultDividerLocation = defaultDividerLocation; } // // implementation // @Override public void paint(Graphics g) { super.paint(g); if (!painted) { painted = true; this.setDividerLocation(currentDividerLocation); } dividerPositionCaptured = false; } private class DividerLocator extends ComponentAdapter { @Override public void componentResized(ComponentEvent e) { setDividerLocation(currentDividerLocation); } } private class DividerMovedByUserComponentAdapter extends ComponentAdapter { @Override public void componentResized(ComponentEvent e) { if (dividerPositionCaptured == false) { dividerPositionCaptured = true; currentDividerLocation = (double) first.getWidth() / (double)(first.getWidth() + second.getWidth()); System.out.println(currentDividerLocation); } } } } class SplitPaneWrapper extends JPanel { private final JSplitPane splitPane; protected SplitPaneWrapper(JSplitPane splitPane) { super(new BorderLayout()); this.splitPane = splitPane; splitPane.setResizeWeight(.5); add(splitPane); } private static int getOrientedSize(JSplitPane sp) { return sp.getOrientation() == JSplitPane.VERTICAL_SPLIT ? sp.getHeight() - sp.getDividerSize() : sp.getWidth() - sp.getDividerSize(); } @Override public void doLayout() { int size = getOrientedSize(splitPane); double d = splitPane.getDividerLocation() / (double) size; BigDecimal bd = new BigDecimal(d).setScale(2, BigDecimal.ROUND_HALF_UP); super.doLayout(); if (splitPane.isShowing()) { EventQueue.invokeLater(() -> { int s = getOrientedSize(splitPane); int iv = (int)(.5 + s * bd.doubleValue()); splitPane.setDividerLocation(iv); }); } } } 

这就是我最终使用的。 它似乎完全按照我的目的去做:创建一个按比例resize的拆分窗格,包括在移动分隔符后按比例resize。

这是gui在resize之前和之后的示例:

在此处输入图像描述

在此处输入图像描述

这就是代码的样子。 这是一个完整的示例,其中包括水平和垂直拆分窗格的拆分窗格的比例resize以及用户移动分隔符的情况。

 import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSplitPane; public class Example { public static void main(String[] args) { new Example().showGui(); } private void showGui() { // create the jframe JFrame jFrame = new JFrame(); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setSize(400, 200); // create the left panel JPanel left = new JPanel(); left.setBackground(Color.yellow); // create the right panel JPanel right = new JPanel(); right.setBackground(Color.orange); // create the bottom panel JPanel bottom = new JPanel(); bottom.setBackground(Color.green); // create the split panes ResizableSplitPane horizontalSplit = new ResizableSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right, jFrame); ResizableSplitPane verticalSplit = new ResizableSplitPane(JSplitPane.VERTICAL_SPLIT, horizontalSplit, bottom, jFrame); jFrame.getContentPane().add(verticalSplit); // show the gui jFrame.setVisible(true); } public class ResizableSplitPane extends JSplitPane { // // instance variables // private boolean painted; private double defaultDividerLocation; private double dividerProportionalLocation; private int currentDividerLocation; private Component first; private Component second; private boolean dividerPositionCaptured = false; // // constructors // public ResizableSplitPane(int splitType, Component first, Component second, Component parent) { this(splitType, first, second, parent, 0.5); } public ResizableSplitPane(int splitType, Component first, Component second, Component parent, double defaultDividerLocation) { super(splitType, first, second); this.defaultDividerLocation = defaultDividerLocation; this.dividerProportionalLocation = defaultDividerLocation; this.setResizeWeight(defaultDividerLocation); this.first = first; this.second = second; parent.addComponentListener(new DividerLocator()); second.addComponentListener(new DividerMovedByUserComponentAdapter()); } // // trivial getters and setters // public double getDefaultDividerLocation() { return defaultDividerLocation; } public void setDefaultDividerLocation(double defaultDividerLocation) { this.defaultDividerLocation = defaultDividerLocation; } // // implementation // @Override public void paint(Graphics g) { super.paint(g); if (painted == false) { painted = true; this.setDividerLocation(dividerProportionalLocation); this.currentDividerLocation = this.getDividerLocation(); } } private class DividerLocator extends ComponentAdapter { @Override public void componentResized(ComponentEvent e) { setDividerLocation(dividerProportionalLocation); currentDividerLocation = getDividerLocation(); } } private class DividerMovedByUserComponentAdapter extends ComponentAdapter { @Override public void componentResized(ComponentEvent e) { System.out.println("RESIZED: " + dividerPositionCaptured); int newDividerLocation = getDividerLocation(); boolean dividerWasMovedByUser = newDividerLocation != currentDividerLocation; System.out.println(currentDividerLocation + "\t" + newDividerLocation + "\t" + dividerProportionalLocation); if (dividerPositionCaptured == false || dividerWasMovedByUser == true) { dividerPositionCaptured = true; painted = false; if(getOrientation() == JSplitPane.HORIZONTAL_SPLIT) { dividerProportionalLocation = (double) first.getWidth() / (double) (first.getWidth() + second.getWidth()); } else { dividerProportionalLocation = (double) first.getHeight() / (double) (first.getHeight() + second.getHeight()); } System.out.println(dividerProportionalLocation); } } } } }