Базовая настройка такова: у меня есть вертикальная JSplitPane, для которой я хочу иметь нижний компонент фиксированного размера и верхний компонент с изменяющимся размером, который я выполнил, вызвав setResizeWeight(1.0)
.В этом приложении есть кнопка для восстановления конфигурации окна «по умолчанию».Высота окна по умолчанию - это высота рабочего стола, а расположение разделителя по умолчанию составляет 100 пикселей от нижней части разделенной панели.
Чтобы установить расположение разделителя на 100 пикселей, я принимаю высоту 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));
}
}
Я подумал о нескольких способах обойти это, но все они кажутся хакерскими.До сих пор лучшей идеей у меня было вызывать f.validate()
между установкой размера кадра и установкой расположения разделителя, но я обеспокоен тем, что могут быть побочные эффекты для принудительного подтверждения на ранней стадии.
Другой вариант, о котором я подумал, - это использовать EventQueue.invokeLater()
, чтобы поставить вызов, чтобы установить расположение делителя в конце очереди событий.Но это кажется мне рискованным - я предполагаю, что JSplitPane будет проверен в этот момент, и я обеспокоен тем, что это ошибочное предположение.
Есть ли лучший способ?