问题描述
我正在试用 JSplitPane
和几个可并排滚动的 JTable
。
但是,我正在尝试一种行为,根据 gif,JScrollPane
收缩得太多。
请注意左侧组件,除了最小 width
为 250px
外,还会继续缩小。
相关代码为
final var objetsTable = new JTable();
final var objectsScrollPane = new JScrollPane(objetsTable);
objectsScrollPane.setMinimumSize(new Dimension(250,0));
objectsScrollPane.setPreferredSize(new Dimension(400,300));
final var stepsTable = new JTable();
final var stepsScrollPane = new JScrollPane(stepsTable);
stepsScrollPane.setMinimumSize(new Dimension(150,0));
stepsScrollPane.setPreferredSize(new Dimension(200,300));
final var splitPane = new JSplitPane();
splitPane.setLeftComponent(objectsScrollPane);
splitPane.setRightComponent(stepsScrollPane);
splitPane.setResizeWeight(1.0);
在这种情况下,如何避免 JScrollPane
收缩太多?
解决方法
对 getMinimumSize
调用的 JSplitPane
返回的大小实际上考虑了其左右 Component
的最小大小,加上分隔符大小。因此,可能解决您的问题的一种方法是让您的 JSplitPane
实现 Scrollable
(以使其尊重自身的最小大小)并将其添加到 JScrollPane
。通过这种方式,您可以确保遵守最小尺寸,并且当用户继续缩小 Scrollable
JSplitPane
超过其最小尺寸时,滚动条将显示。
这是一些工作代码:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class Main {
private static class MyScrollableSplitPane extends JSplitPane implements Scrollable {
private int maxUnitIncrement = 10;
public void setMaxUnitIncrement(final int pixels) {
maxUnitIncrement = pixels;
}
public int getMaxUnitIncrement() {
return maxUnitIncrement;
}
/**
* This is being constantly checked by the scroll pane instead of the
* getPreferredScrollableViewportSize...
*/
@Override
public Dimension getPreferredSize() {
final Dimension minSz = getMinimumSize(),curSz = getSize();
curSz.width = Math.max(curSz.width,minSz.width);
curSz.height = Math.max(curSz.height,minSz.height);
return curSz;
}
/**
* This is only checked once (at the beginning).
*/
@Override
public Dimension getPreferredScrollableViewportSize() {
return super.getPreferredSize();
}
/**
* Source: https://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html .
*/
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect,int orientation,int direction) {
//Get the current position.
int currentPosition;
if (orientation == SwingConstants.HORIZONTAL) {
currentPosition = visibleRect.x;
} else {
currentPosition = visibleRect.y;
}
//Return the number of pixels between currentPosition
//and the nearest tick mark in the indicated direction.
if (direction < 0) {
int newPosition = currentPosition -
(currentPosition / maxUnitIncrement)
* maxUnitIncrement;
return (newPosition == 0) ? maxUnitIncrement : newPosition;
} else {
return ((currentPosition / maxUnitIncrement) + 1)
* maxUnitIncrement
- currentPosition;
}
}
/**
* Source: https://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html .
*/
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect,int direction) {
if (orientation == SwingConstants.HORIZONTAL) {
return visibleRect.width - maxUnitIncrement;
} else {
return visibleRect.height - maxUnitIncrement;
}
}
@Override
public boolean getScrollableTracksViewportWidth() {
final Container parent = getParent();
return (parent instanceof JViewport) && (getMinimumSize().width < ((JViewport) parent).getWidth());
}
@Override
public boolean getScrollableTracksViewportHeight() {
final Container parent = getParent();
return (parent instanceof JViewport) && (getMinimumSize().height < ((JViewport) parent).getHeight());
}
}
private static void createAndShowGUI() {
/*Since I don't add any Components to the 'left' and 'right' panels,I am going to set the
preferred size of them. This is only for demonstrating the concept. Setting the minimum size
though is somewhat required by the JSplitPane itself.*/
final JPanel left = new JPanel();
left.setMinimumSize(new Dimension(150,100));
left.setPreferredSize(new Dimension(200,200));
final JPanel right = new JPanel();
right.setMinimumSize(new Dimension(300,100));
right.setPreferredSize(new Dimension(400,200));
final JSplitPane split = new MyScrollableSplitPane();
split.setBorder(BorderFactory.createLineBorder(Color.CYAN.darker(),3));
split.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
split.setLeftComponent(left);
split.setRightComponent(right);
final JFrame frame = new JFrame("MyScrollableSplitPane demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(split));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}