From cacf0ea9871971c593ef969a350dfe93550860e9 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Tue, 4 May 2021 21:39:08 +0200 Subject: [PATCH] ComboBox: support using as cell renderer (e.g. in `JTable`) --- CHANGELOG.md | 9 +-- .../formdev/flatlaf/ui/FlatArrowButton.java | 23 +++++-- .../formdev/flatlaf/ui/FlatComboBoxUI.java | 68 +++++++++++++------ .../flatlaf/testing/FlatComponents2Test.java | 20 ++++++ 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ed1b298..5bc46474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,13 @@ FlatLaf Change Log #### New features and improvements +- Renamed `Flat*Laf.install()` methods to `Flat*Laf.setup()` to avoid confusion + with `UIManager.installLookAndFeel(LookAndFeelInfo info)`. The old + `Flat*Laf.install()` methods are still there, but marked as deprecated. They + will be removed in a future version. - Button and ToggleButton: Support borderless button style (set client property `JButton.buttonType` to `borderless`). (PR #276) +- ComboBox: Support using as cell renderer (e.g. in `JTable`). - DesktopPane: Improved layout of iconified internal frames in dock: - Always placed at bottom-left in desktop pane. - Newly iconified frames are added to the right side of the dock. @@ -23,10 +28,6 @@ FlatLaf Change Log - Use mapper function in color filter to dynamically map colors. (PR #303) - Color filter supports light and dark themes. - Getters for icon name, classloader, etc. -- Renamed `Flat*Laf.install()` methods to `Flat*Laf.setup()` to avoid confusion - with `UIManager.installLookAndFeel(LookAndFeelInfo info)`. The old - `Flat*Laf.install()` methods are still there, but marked as deprecated. They - will be removed in a future version. #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java index 26916d89..132e670d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java @@ -141,6 +141,21 @@ public class FlatArrowButton return FlatUIUtils.deriveColor( foreground, this.foreground ); } + /** + * Returns the color used to paint the arrow. + * + * @since 1.2 + */ + protected Color getArrowColor() { + return isEnabled() + ? (pressedForeground != null && isPressed() + ? pressedForeground + : (hoverForeground != null && isHover() + ? hoverForeground + : foreground)) + : disabledForeground; + } + @Override public Dimension getPreferredSize() { return scale( super.getPreferredSize() ); @@ -170,13 +185,7 @@ public class FlatArrowButton } // paint arrow - g.setColor( deriveForeground( isEnabled() - ? (pressedForeground != null && isPressed() - ? pressedForeground - : (hoverForeground != null && isHover() - ? hoverForeground - : foreground)) - : disabledForeground ) ); + g.setColor( deriveForeground( getArrowColor() ) ); paintArrow( (Graphics2D) g ); FlatUIUtils.resetRenderingHints( g, oldRenderingHints ); 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 2b335cf0..f1b7b948 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 @@ -42,6 +42,7 @@ import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import javax.swing.AbstractAction; import javax.swing.BorderFactory; +import javax.swing.CellRendererPane; import javax.swing.ComboBoxEditor; import javax.swing.DefaultListCellRenderer; import javax.swing.InputMap; @@ -390,6 +391,15 @@ public class FlatComboBoxUI public void update( Graphics g, JComponent c ) { float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); float arc = FlatUIUtils.getBorderArc( c ); + boolean paintBackground = true; + + // check whether used as cell renderer + boolean isCellRenderer = c.getParent() instanceof CellRendererPane; + if( isCellRenderer ) { + focusWidth = 0; + arc = 0; + paintBackground = isCellRendererBackgroundChanged(); + } // fill background if opaque to avoid garbage if user sets opaque to true if( c.isOpaque() && (focusWidth > 0 || arc > 0) ) @@ -407,27 +417,29 @@ public class FlatComboBoxUI boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight(); // paint background - g2.setColor( getBackground( enabled ) ); - FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); - - // paint arrow button background - if( enabled ) { - g2.setColor( paintButton ? buttonEditableBackground : buttonBackground ); - Shape oldClip = g2.getClip(); - if( isLeftToRight ) - g2.clipRect( arrowX, 0, width - arrowX, height ); - else - g2.clipRect( 0, 0, arrowX + arrowWidth, height ); + if( paintBackground || c.isOpaque() ) { + g2.setColor( getBackground( enabled ) ); FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); - g2.setClip( oldClip ); - } - // paint vertical line between value and arrow button - if( paintButton ) { - g2.setColor( enabled ? borderColor : disabledBorderColor ); - float lw = scale( 1f ); - float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw; - g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) ); + // paint arrow button background + if( enabled && !isCellRenderer ) { + g2.setColor( paintButton ? buttonEditableBackground : buttonBackground ); + Shape oldClip = g2.getClip(); + if( isLeftToRight ) + g2.clipRect( arrowX, 0, width - arrowX, height ); + else + g2.clipRect( 0, 0, arrowX + arrowWidth, height ); + FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); + g2.setClip( oldClip ); + } + + // paint vertical line between value and arrow button + if( paintButton ) { + g2.setColor( enabled ? borderColor : disabledBorderColor ); + float lw = scale( 1f ); + float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw; + g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2)) ); + } } // avoid that the "current value" renderer is invoked with enabled antialiasing @@ -554,6 +566,16 @@ public class FlatComboBoxUI } } + private boolean isCellRenderer() { + return comboBox.getParent() instanceof CellRendererPane; + } + + private boolean isCellRendererBackgroundChanged() { + // parent is a CellRendererPane, parentParent is e.g. a JTable + Container parentParent = comboBox.getParent().getParent(); + return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() ); + } + //---- class FlatComboBoxButton ------------------------------------------- protected class FlatComboBoxButton @@ -580,6 +602,14 @@ public class FlatComboBoxUI protected boolean isPressed() { return super.isPressed() || (!comboBox.isEditable() ? pressed : false); } + + @Override + protected Color getArrowColor() { + if( isCellRenderer() && isCellRendererBackgroundChanged() ) + return comboBox.getForeground(); + + return super.getArrowColor(); + } } //---- class FlatComboPopup ----------------------------------------------- diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java index efa95f0b..117a91a3 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponents2Test.java @@ -134,6 +134,7 @@ public class FlatComponents2Test "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; + cm.getColumn(2).setCellRenderer( new TestComboBoxTableCellRenderer() ); cm.getColumn(2).setCellEditor( new DefaultCellEditor( new JComboBox<>( months ) ) ); JComboBox editableComboBox = new JComboBox<>( months ); editableComboBox.setEditable( true ); @@ -1219,4 +1220,23 @@ public class FlatComponents2Test return this; } } + + //---- class TestComboBoxTableCellRenderer -------------------------------- + + private static class TestComboBoxTableCellRenderer + extends JComboBox + implements TableCellRenderer + { + @Override + public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, + boolean hasFocus, int row, int column ) + { + setModel( new DefaultComboBoxModel<>( new String[] { String.valueOf( value ) } ) ); + + setBackground( isSelected ? table.getSelectionBackground() : table.getBackground() ); + setForeground( isSelected ? table.getSelectionForeground() : table.getForeground() ); + setBorder( null ); + return this; + } + } }