基本设置是这样的:我有一个垂直的JSplitPane,我希望有一个固定大小的底部组件和一个调整大小的顶部组件,我通过调用setResizeWeight(1.0)完成.在此应用程序中,有一个用于恢复“默认”窗口配置的按钮.窗口的默认高度是桌面高度,默认分隔符位置距离拆分窗格底部100个像素.
要将分隔符位置设置为100px,我将采用JSplitPane高度 – 100.问题是,在此之前我调整了JFrame的大小,并且由于代码处于按钮回调中,因此JSplitPane已失效但尚未调整大小.因此分配器位置设置不正确.
这是一个SSCCE.单击按钮两次以查看问题.第一次单击将调整窗口大小,但分隔符位置保持不变(相对于窗口底部).第二次单击正确移动分隔符,因为窗口大小没有改变.
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GraphicsConfiguration; import java.awt.Insets; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JSplitPane; public class SSCCE { /** * @param args unused */ public static void main(String[] args) { new SSCCE(); } private final JFrame f = new JFrame("JSplitPane SSCE"); private final JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT,true); public SSCCE() { f.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE); sp.add(new JLabel("top")); sp.add(new JLabel("bottom")); sp.setResizeWeight(1.0); f.getContentPane().add(sp); f.getContentPane().add(new JButton(new AbstractAction("Resize to Default") { @Override public void actionPerformed(ActionEvent e) { restoreDefaults(); } }),BorderLayout.PAGE_END); f.setSize(400,300); f.setVisible(true); } void restoreDefaults() { f.setSize(f.getWidth(),getDesktopRect(f.getGraphicsConfiguration()).height); sp.setDividerLocation(sp.getSize().height - 100); // Does not work on first button press } Rectangle getDesktopRect(GraphicsConfiguration gc) { Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension size = toolkit.getScreenSize(); Insets insets = toolkit.getScreenInsets(gc); return new Rectangle(insets.left,insets.top,size.width - (insets.left + insets.right),size.height - (insets.top + insets.bottom)); } }
我想到了一些可能解决这个问题的方法,但它们看起来都像是一种hackish.到目前为止,我最好的想法是在设置帧大小和设置分隔符位置之间调用f.validate(),但我担心可能会有早期强制验证的副作用.
我想到的另一个选项是使用EventQueue.invokeLater()来调用以在事件队列的末尾设置分隔符位置.但这对我来说似乎有风险 – 我假设JSplitPane将在那时得到验证,而我担心这可能是一个错误的假设.
有没有更好的办法?
解决方法
花了一段时间(可能是因为在这里清晨:-)了解问题,所以只是为了确保我得到它:
>底部组件的大小可以是用户始终决定的任何大小
>调整框架大小时,顶部组件应发生所有高度变化
>可以选择恢复默认大小,与之前的任何设置无关
>“default”表示底部组件必须具有固定高度xx
如果是这样,解决方案是将框架尺寸调整与底部部件的尺寸分离.你的第二个选择是死的:调整框架的大小并将底部的comp调整大小包装成一个invokeLater(EventQueue或SwingUtilities,无关紧要).
void restoreDefaults() { f.setSize(f.getWidth(),getDesktopRect(f.getGraphicsConfiguration()).height); SwingUtilities.invokeLater(new Runnable() { public void run() { sp.setDividerLocation(sp.getSize().height - 100); } }); }
这保证按预期工作,因为invokeLater在所有已经排队的事件之后将请求放在最后:
/** * Causes <i>doRun.run()</i> to be executed asynchronously on the * AWT event dispatching thread. This will happen after all * pending AWT events have been processed. [...] * If invokeLater is called from the event dispatching thread -- * for example,from a JButton's ActionListener -- the <i>doRun.run()</i> will * still be deferred until all pending events have been processed.