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

标签 java swing jsplitpane

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

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

这是 GUI 最初的样子。

enter image description here

这是几次调整大小后的样子。
enter image description here

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

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/

相关文章:

Java类的组织

java - 如何在Eclipse中检查项目内的所有文件是否已保存?

java - Microsoft][ODBC 驱动程序管理器] 字符串或缓冲区长度无效

java - (Gridbag 布局)图形组件被剪切到另一个网格中,不知道为什么

java - 单击按钮时如何禁用面板的组件

java - 从 Netbeans 中的现有实体生成表

java - JSplitPane 调整大小行为

java - 在 JSplitPane 上设置分隔线位置不起作用

java - 等待 JFrame 加载后再继续?

java - exec 命令在 php 脚本中不起作用