我想实现一个JSplitPane(水平分割),其中右边的组件有一个固定的宽度,即当分隔符被拖动时,它会跳回正确的大小,除非分隔符被拖到足够远的右边,在这种情况下,最右边的组件将有零宽度。
要重新显示右侧组件,用户可以向左拖动分隔符。
我已经得到了这个主要工作,但是当我根据我改变窗口大小的多少和多快来调整窗口大小时,分隔符跳跃显示或隐藏正确的组件,因为我想要的是它不应该改变"状态",即如果正确的组件不可见,那么它应该保持不可见,反之亦然。
我已经尝试了很多东西,但主要的障碍是,似乎没有办法知道分隔符是由用户通过鼠标拖动的,还是代码(我的分隔符逻辑和/或JSplitPane内部逻辑)改变了分隔符的位置。
这是一个独立的测试用例,运行它并尝试拖动水平分隔符来隐藏和显示右侧面板,并使用那些隐藏/显示尝试调整窗口的大小。
在Mac OS X Java 1.6 (Apple)或Java 7 (Oracle)上无法正常工作。使用Oracle的东西,渲染要慢得多,问题也更严重。调整窗口大小可以缓慢地工作,但快速更改窗口大小会导致问题。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import net.miginfocom.swing.MigLayout;
public class SplitTest {
public static class MySplitPane extends JSplitPane {
boolean m_RightCollapsed;
public MySplitPane(int orientation, JComponent left, JComponent right) {
super(orientation, left, right);
addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
}
});
addComponentListener(new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
reposDivider();
}
@Override
public void componentResized(ComponentEvent e) {
reposDivider();
}
@Override
public void componentMoved(ComponentEvent e) {
reposDivider();
}
@Override
public void componentHidden(ComponentEvent e) {
}
});
}
public void reposDivider() {
setDividerLocation(getDividerLocation());
}
public void setDividerLocation(int location) {
int newLocation;
m_RightCollapsed = location > getSize().width - getRightComponent().getPreferredSize().width / 2;
if (m_RightCollapsed)
newLocation = getSize().width;
else
newLocation = getSize().width - getInsets().right - getDividerSize() - getRightComponent().getPreferredSize().width;
super.setDividerLocation(newLocation);
}
}
static class MyScrollable extends JPanel implements Scrollable {
int m_Height;
public MyScrollable(int height) {
m_Height = height;
}
@Override
public void paint(java.awt.Graphics g) {
super.paint(g);
g.setColor(Color.CYAN);
g.fillOval(0, 0, getWidth(), 500);
}
@Override
public Dimension getPreferredScrollableViewportSize() {
//return super.getPreferredSize();
return new Dimension(100, m_Height);
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
// TODO Auto-generated method stub
return 10;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 20;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
public static class ShrinkGrow extends JPanel {
public ShrinkGrow(final JComponent component, final JSplitPane split) {
JButton grow = new JButton("+++");
JButton shrink = new JButton("---");
add(grow);
add(shrink);
grow.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Dimension oldSize = component.getPreferredSize();
Dimension newSize = new Dimension(oldSize.width, oldSize.height + 10);
component.setPreferredSize(newSize);
component.setSize(newSize);
}
});
shrink.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Dimension oldSize = component.getPreferredSize();
Dimension newSize = new Dimension(oldSize.width, oldSize.height - 10);
component.setPreferredSize(newSize);
component.setSize(newSize);
}
});
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
JPanel mainView = new JPanel();
JPanel top = new JPanel();
top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS));
JPanel bottom = new JPanel();
bottom.setLayout(new BoxLayout(bottom, BoxLayout.Y_AXIS));
final JSplitPane rightSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
JPanel topContent = new MyScrollable(200);
JPanel topFixed = new ShrinkGrow(topContent, rightSplit);
topFixed.setLayout(new BoxLayout(topFixed, BoxLayout.X_AXIS));
JScrollPane topFlexible = new JScrollPane(topContent);
topFlexible.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
topFlexible.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
JPanel bottomContent = new MyScrollable(300);
JPanel bottomFixed = new ShrinkGrow(bottomContent, rightSplit);
bottomFixed.setLayout(new BoxLayout(bottomFixed, BoxLayout.X_AXIS));
JScrollPane bottomFlexible = new JScrollPane(bottomContent);
bottomFlexible.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
bottomFlexible.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
mainView.setBackground(Color.red);
topFixed.setBackground(Color.green);
topContent.setBackground(Color.green.darker());
bottomFixed.setBackground(Color.blue);
bottomContent.setBackground(Color.blue.darker());
mainView.setMinimumSize(new Dimension(100, 100));
mainView.setPreferredSize(new Dimension(400, 300));
mainView.setMaximumSize(new Dimension(10000, 10000));
topFixed.setMinimumSize(new Dimension(topFixed.getMinimumSize().width, 30));
topFixed.setPreferredSize(new Dimension(topFixed.getPreferredSize().width, 30));
topFixed.setMaximumSize(new Dimension(topFixed.getMaximumSize().width, 30));
bottomFixed.setMinimumSize(new Dimension(bottomFixed.getMinimumSize().width, 40));
bottomFixed.setPreferredSize(new Dimension(bottomFixed.getPreferredSize().width, 40));
bottomFixed.setMaximumSize(new Dimension(bottomFixed.getMaximumSize().width, 40));
topContent.setPreferredSize(new Dimension(100, 500));
bottomContent.setPreferredSize(new Dimension(100, 400));
top.add(topFixed);
top.add(topFlexible);
bottom.add(bottomFixed);
bottom.add(bottomFlexible);
rightSplit.setLeftComponent(top);
rightSplit.setRightComponent(bottom);
rightSplit.setMinimumSize(new Dimension(0, 0));
final JSplitPane mainSplit = new MySplitPane(JSplitPane.HORIZONTAL_SPLIT, mainView, rightSplit);
window.add(mainSplit);
window.pack();
window.setVisible(true);
}
}
不确定是否可以捕获dragging
事件,但可以肯定您可以捕获propertyChange
事件。通过PropertyChangeListener
JSplitPane类可以在移动JSplitPane
的分隔符后捕获事件。确保提供DIVIDER_LOCATION_PROPERTY
作为参数,以便此侦听器将侦听修改过的分隔器位置事件。如果您没有将其作为addPropertyChangeListener()
方法中的第一个参数提供,则如果PropertyChangeEvent
的getPropertyName()
方法返回dividerLocation
作为值,则始终可以放置条件语句。
jSplitPane1.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
// do here
}
});
为JSplitPane分隔符添加一个mousellistener来检测分隔符何时被拖动。拖动时,响应属性更改事件。示例:
https://community.oracle.com/thread/1352161?start=0& tstart = 0
SplitPaneUI spui = splitPane.getUI();
if (spui instanceof BasicSplitPaneUI) {
// Setting a mouse listener directly on split pane does not work, because no events are being received.
((BasicSplitPaneUI) spui).getDivider().addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
…除非分隔符向右拖动到足够远的位置在这种情况下大多数组件的宽度为零。
要重新显示正确的组件,用户可以拖动分隔符离左边足够远
听起来你只需要禁用splitPane来禁用拖动,
则setOneTouchExpandable()为true。您可能需要删除其中一个'可扩展'
按钮禁用错误展开方式