If more tabs exist than can have their label text displayed then WindowBuilder has an error when rendering. The source below has a label "Oops" which forces the combined width of all the tab titles to push some tabs out of sight. If you try and render the page you get the error.
If you edit "Oops" down to "A" you will be able to view the design.
Tabs.java
Some diagnosis has come up with the following theory (thanks to Claude)
The exact line:
// org.eclipse.wb.swing/.../JTabbedPaneInfo.java:113
Rectangle bounds = CoordinateUtils.get(pane.getBoundsAt(i));
is passing the result of JTabbedPane.getBoundsAt(i) straight into CoordinateUtils.get(java.awt.Rectangle) (line 49 of CoordinateUtils.java), which dereferences o.x with no null check.
And JTabbedPane.getBoundsAt(int) is documented to return null — straight from the JDK 21 source:
▎ Returns the tab bounds at index. If the tab at this index is not currently visible in the UI, then returns null. If there is no UI set on this tabbedpane, then returns null.
So when one tab is wide enough that the UI delegate decides it isn't currently visible (e.g. it doesn't fit and gets clipped/scrolled out), getBoundsAt legitimately returns null and WindowBuilder NPEs.
Why long text triggers it specifically on macOS: WindowBuilder renders your Swing live in-process. On macOS the default L&F is Aqua, whose AquaTabbedPaneCopyFromBasicUI enables a scrollable / overflow
tab layout — tabs that don't fit in the visible header strip are treated as not-currently-visible and getTabBounds returns null for them. BasicTabbedPaneUI (Metal etc.) uses WRAP and always produces a
Rectangle, which is why the cross-platform L&F doesn't reproduce it.
Fix in WindowBuilder
Line 113 needs a null guard. Minimal patch in JTabbedPaneInfo.getTabs():
java.awt.Rectangle rawBounds = pane.getBoundsAt(i);
if (rawBounds == null) {
continue; // tab not currently visible — skip, don't NPE
}
Rectangle bounds = CoordinateUtils.get(rawBounds);
tabs.add(new JTabbedPaneTabInfo(this, component, bounds));
Worth reporting upstream — the Javadoc on getBoundsAt has documented the null return for years.
Workarounds (without patching WB)
Shorten the offending tab title so all tabs fit Aqua's header strip.
Force Metal at the top of Tabs.main (or in a static {} block) so WB renders with Metal instead of Aqua:
try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); }
catch (Exception ignored) {}
WindowBuilder evaluates static initializers and the constructor when rendering, so this swaps the UI delegate to BasicTabbedPaneUI and the NPE goes away.
If more tabs exist than can have their label text displayed then WindowBuilder has an error when rendering. The source below has a label "Oops" which forces the combined width of all the tab titles to push some tabs out of sight. If you try and render the page you get the error.
If you edit "Oops" down to "A" you will be able to view the design.
Tabs.java
Some diagnosis has come up with the following theory (thanks to Claude)
The exact line:
// org.eclipse.wb.swing/.../JTabbedPaneInfo.java:113
Rectangle bounds = CoordinateUtils.get(pane.getBoundsAt(i));
is passing the result of JTabbedPane.getBoundsAt(i) straight into CoordinateUtils.get(java.awt.Rectangle) (line 49 of CoordinateUtils.java), which dereferences o.x with no null check.
And JTabbedPane.getBoundsAt(int) is documented to return null — straight from the JDK 21 source:
▎ Returns the tab bounds at index. If the tab at this index is not currently visible in the UI, then returns null. If there is no UI set on this tabbedpane, then returns null.
So when one tab is wide enough that the UI delegate decides it isn't currently visible (e.g. it doesn't fit and gets clipped/scrolled out), getBoundsAt legitimately returns null and WindowBuilder NPEs.
Why long text triggers it specifically on macOS: WindowBuilder renders your Swing live in-process. On macOS the default L&F is Aqua, whose AquaTabbedPaneCopyFromBasicUI enables a scrollable / overflow
tab layout — tabs that don't fit in the visible header strip are treated as not-currently-visible and getTabBounds returns null for them. BasicTabbedPaneUI (Metal etc.) uses WRAP and always produces a
Rectangle, which is why the cross-platform L&F doesn't reproduce it.
Fix in WindowBuilder
Line 113 needs a null guard. Minimal patch in JTabbedPaneInfo.getTabs():
java.awt.Rectangle rawBounds = pane.getBoundsAt(i);
if (rawBounds == null) {
continue; // tab not currently visible — skip, don't NPE
}
Rectangle bounds = CoordinateUtils.get(rawBounds);
tabs.add(new JTabbedPaneTabInfo(this, component, bounds));
Worth reporting upstream — the Javadoc on getBoundsAt has documented the null return for years.
Workarounds (without patching WB)
Shorten the offending tab title so all tabs fit Aqua's header strip.
Force Metal at the top of Tabs.main (or in a static {} block) so WB renders with Metal instead of Aqua:
try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); }
catch (Exception ignored) {}
WindowBuilder evaluates static initializers and the constructor when rendering, so this swaps the UI delegate to BasicTabbedPaneUI and the NPE goes away.