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

时间:2016-03-17 17:27:10

标签: java swing jsplitpane

在调整容器大小时,我无法让JSplitPane保持相同的相对位置。如果假设拆分窗格具有固定位置,则一切正常。我可以使用下面显示的代码使分隔符位置保持接近相同的相对位置,但是在调整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);
                }
            }
        }

    }

}

2 个答案:

答案 0 :(得分:2)

  • 这是我的尝试:
    • 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);
      });
    }
  }
}

答案 1 :(得分:1)

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

这是gui在调整大小之前和之后的示例:

enter image description here

enter image description here

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

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

    }

}