Нужна высота недействительный компонент Swing

Базовая установка такова: у меня есть вертикальная 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 будет проверен на этом этапе, и меня беспокоит, что это может быть ошибочное предположение.

Есть ли способ лучше?

6
задан mKorbel 5 August 2011 в 06:40
поделиться