MigLayout error: “Unstable cyclic dependency in ab

2019-05-11 16:24发布

问题:

Why does this SSCCE (with MigLayout libraries) ...

public static void main(String[] args) {

    try {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
        e.printStackTrace();
    }

    JFrame frame = new JFrame();
    frame.setLayout(new MigLayout(new LC().fill().insetsAll("0")));

    JTabbedPane jtp = new JTabbedPane();
    jtp.add(new JPanel(), "Tab 1");
    jtp.add(new JPanel(), "Tab 2");

    JLabel label = new JLabel("label");

    JPanel panel = new JPanel(new MigLayout(new LC().fill()));
    panel.add(jtp, "id tabbedpane, grow, span");
    panel.add(label, "pos (tabbedpane.w-label.w) 10, id label");
    label.setBounds(100, 100, 10, 10);

    frame.add(panel, "grow, span");
    frame.setSize(500, 500);
    frame.setLocationRelativeTo(null); // Sorry, Andrew Thompson
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

Throw this error:

Unstable cyclic dependency in absolute linked values!
Unstable cyclic dependency in absolute linked values!
Unstable cyclic dependency in absolute linked values!
Unstable cyclic dependency in absolute linked values!

?

I figured it out that if you remove the WindowsLookAndFeel code, then everything runs fine...

So, this is a problem with MigLayout and the WindowsLookAndFeel. Yet my real application necessitates its use.

EDIT:

This is what the frame looks like when the error is thrown:

回答1:

Taking a look at the source code, this happens as it makes corrections to the size of the components while it's doing the layout. If it makes more than count * 8 + 10 corrections, then it short circuits the code to prevent an infinite loop.

The relevant source (with some stuff removed) is:

do {
    doAgain = false;
    for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
        ArrayList<CompWrap> compWraps = it.next().compWraps;
        for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
            CompWrap cw = compWraps.get(i);

            if (j == 0) {
                doAgain |= doAbsoluteCorrections(cw, bounds);
                // . . .
            }

            // . . .
        }
    }
    clearGroupLinkBounds();
    if (++count > ((compCount << 3) + 10)) {
        System.err.println("Unstable cyclic dependency in absolute linked values!");
        break;
    }

} while (doAgain);

So what's happening is that if doAbsoluteCorrections returns true (which it does if any components change size when corrections are done to satisfy sizing dependencies) then it will repeat the loop, which does the corrections again. What you're seeing is the warning message it prints when it repeats this too many times. Since the corrections can result in changes to the sizes of linked components, you can get a situation where the corrections unset a y-value for one component and sets the y-value for the other, then when that first component has its y-value set, it un-sets the y-value for the other, and this repeats until we run out of retries.

The Windows L&F caused this problem very often for me because it seemed like the components would always settle into a situation where they would do this correction and only get changed by 1 pixel for the correction, but that correction caused it to need to redo the layout for another component that caused it to shift 1 pixel back. The "recursion" (if you want to think of it that way) was unstable and didn't arrive at a stable solution.

I don't know what the solution is to remove those messages, but if it's not causing unusual "jiggling" in your application (you'll know what I mean if it is), I wouldn't worry about it. It's just a message to indicate that it's giving up on the corrections because it's recursed too many times.