diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f7a1a6..b35cfd52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ FlatLaf Change Log - MenuItem: Changed accelerator delimiter from `-` to `+`. (Windows and Linux). - ComboBox: Fixed occasional `StackOverflowError` when modifying combo box not on AWT thread. (issue #432) +- macOS: Fixed `NullPointerException` when using AWT component + `java.awt.Choice`. (issue #439) ## 1.6.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 8794c3d8..477ee32a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -260,7 +260,10 @@ public class FlatComboBoxUI public void layoutContainer( Container parent ) { super.layoutContainer( parent ); - if( arrowButton != null ) { + // on macOS, a Swing combo box is used for AWT component java.awt.Choice + // and the font may be (temporary) null + + if( arrowButton != null && comboBox.getFont() != null ) { // limit button width to height of a raw combobox (without insets) FontMetrics fm = comboBox.getFontMetrics( comboBox.getFont() ); int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java index 94c65fa9..a7178ea5 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java @@ -121,6 +121,10 @@ public class FlatPopupFactory popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() ) return popup; + // avoid endless loop (should newer happen; PopupFactory cache size is 5) + if( ++count > 10 ) + return popup; + // remove contents component from popup window if( popupWindow instanceof JWindow ) ((JWindow)popupWindow).getContentPane().removeAll(); @@ -128,10 +132,6 @@ public class FlatPopupFactory // dispose unused popup // (do not invoke popup.hide() because this would cache the popup window) popupWindow.dispose(); - - // avoid endless loop (should newer happen; PopupFactory cache size is 5) - if( ++count > 10 ) - return popup; } } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAWTTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAWTTest.java new file mode 100644 index 00000000..2a9691f1 --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAWTTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.testing; + +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import com.formdev.flatlaf.FlatLightLaf; + +/** + * Used to test AWT components on macOS, which internally use Swing. + * + * @author Karl Tauber + */ +public class FlatAWTTest +{ + public static void main( String[] args ) { + EventQueue.invokeLater( () -> { + FlatLightLaf.setup(); + + Frame frame = new Frame( "FlatAWTTest" ); + frame.addWindowListener( new WindowAdapter() { + @Override + public void windowClosing( WindowEvent e ) { + System.exit( 0 ); + } + } ); + frame.setLayout( new FlowLayout() ); + + frame.add( new Label( "text" ) ); + frame.add( new Button( "text" ) ); + frame.add( new Checkbox( "text" ) ); + + CheckboxGroup checkboxGroup = new CheckboxGroup(); + frame.add( new Checkbox( "radio 1", true, checkboxGroup ) ); + frame.add( new Checkbox( "radio 2", false, checkboxGroup ) ); + frame.add( new Checkbox( "radio 3", false, checkboxGroup ) ); + + Choice choice = new Choice(); + choice.add( "item 1" ); + choice.add( "item 2" ); + choice.add( "item 3" ); + frame.add( choice ); + + frame.add( new TextField( "text" ) ); + frame.add( new TextArea( "text" ) ); + + List list = new List(); + list.add( "item 1" ); + list.add( "item 2" ); + frame.add( list ); + + frame.add( new Scrollbar() ); + frame.add( new ScrollPane() ); + frame.add( new Panel() ); + frame.add( new Canvas() ); + + frame.setSize( 800, 600 ); + frame.setVisible( true ); + }); + } +}