我无法让 JSplitPane 在调整其容器大小时保持相同的相对位置。如果假定拆分 Pane 具有固定位置,则一切正常。我可以使用下面显示的代码使分隔线位置保持接近相同的相对位置,但是当调整 JFrame 大小时分隔线向左移动。如果缓慢调整 JFrame 的大小,偏移会更大。如果 JFrame 变小或变大,则向左移动。
如何让分隔线保持在完全相同的比例位置?
这是 GUI 最初的样子。
这就是代码的样子。此尝试基于此处提供的信息:
JSplitPane splitting 50% precisely
JSplitPane SetDividerLocation Problem
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
父组件的doLayout
方法,在JSplitPane
缩放完成后,调整JSplitPane
的位置分隔线。
- 重写
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);
});
}
}
}
关于java - 如果用户移动了分隔线的位置,如何让 JSplitPane 保持相同的比例位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36067690/