Jakub Čech Jakub Čech - 1 month ago 4
Java Question

invokeLater runs too early

I have JPanel which contains JSplitPane. The JPanel is injected during a runtime into a JFrame using the method invokeAndWait. Then the invokeLater is called to update divider location in SplitPane.

The problem is, when the divider update is invoked, JPanel width is still 0.

When I add sleep or a breakpoint anywhere in the code (except the invokeLater), the code works fine.

final JPanel viewPanel = new JPanel();
viewPanel.setLayout(new BorderLayout());

final JPanel header = getPresenterHeader(getPageTitle(), getPageInstructions());
viewPanel.add(header, BorderLayout.NORTH);
viewPanel.add(getSplitPane(), BorderLayout.CENTER);

toolbar = createActionsToolBar();
toolbar.addAction(new ExitPresenterAction(this));
viewPanel.add(toolbar, BorderLayout.SOUTH);
addContent(viewPanel);

SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
splitPane.setDividerLocation(0.5);
}
});

Answer

I'm not sure whether it helps for you, but we have a method which mostly helps in this situation:

public static JSplitPane setDividerLocation(final JSplitPane splitter, final double proportion) {
    if (splitter.isShowing()) {
        if ((splitter.getWidth() > 0) && (splitter.getHeight() > 0)) {
            splitter.setDividerLocation(proportion);
        } else {
            splitter.addComponentListener(new ComponentAdapter() {
                @Override
                public void componentResized(ComponentEvent ce) {
                    splitter.removeComponentListener(this);
                    setDividerLocation(splitter, proportion);
                }
            });
        }
    } else {
        splitter.addHierarchyListener(new HierarchyListener() {
            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                if (((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) && splitter.isShowing()) {
                    splitter.removeHierarchyListener(this);
                    setDividerLocation(splitter, proportion);
                }
            }
        });
    }
    return splitter;
}

Use it instead of invokeLater call

setDividerLocation(splitPane, 0.5);
Comments