I'm developing a new look and feel for Java; this look and feel imports the Material-style.
I had used the UIDefault for import the change inside the look and feel, so now I must uninstall the look and feel and I have a problem with this operation.
The look and feel con not removed correctly, now I've used for all operation the UIDefault map and I think this is an error because my constant override the old constant and when I go to remove my look and feel. the new look and feel don't override my constant
This is how I'm using the UIDefault
@Override
protected void initComponentDefaults(UIDefaults table) {
super.initComponentDefaults(table);
table.put("Button.highlight", MaterialColors.GRAY_400);
table.put("Button.opaque", false);
table.put("Button.border", BorderFactory.createEmptyBorder(7, 17, 7, 17));
table.put("Button.background", MaterialColors.GRAY_200);
table.put("Button.foreground", MaterialColors.COSMO_BLACK);
table.put("Button.disabledBackground", MaterialColors.COSMO_DARK_GRAY);
table.put("Button.disabledForeground", MaterialColors.BLACK);
table.put("Button[Default].background", MaterialColors.LIGHT_BLUE_500);
table.put("Button[Default].foreground", Color.WHITE);
table.put("Button.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.BOLD));
//table.put("Button[Default].mouseHoverColor", MaterialColors.LIGHT_BLUE_200);
table.put("Button.mouseHoverColor", MaterialColors.GRAY_500);
table.put("Button.mouseHoverEnable", true);
table.put("Button.focusable", true);
table.put("Button[focus].color", MaterialColors.GRAY_900);
table.put("Button.disabledText", MaterialColors.GRAY_600);
table.put("CheckBox.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.BOLD));
table.put("CheckBox.background", MaterialColors.WHITE);
table.put("CheckBox.foreground", MaterialColors.BLACK);
table.put("CheckBox.disabledText", MaterialColors.COSMO_STRONG_GRAY);
table.put("CheckBox.icon", new ImageIcon(MaterialImageFactory.getInstance().getImage(MaterialImageFactory.UNCHECKED_BLACK_BOX)));
table.put("CheckBox.selectedIcon", new ImageIcon(MaterialImageFactory.getInstance().getImage(MaterialImageFactory.CHECKED_BLACK_BOX)));
table.put("ComboBox.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.REGULAR));
table.put("ComboBox.background", MaterialColors.WHITE);
table.put("ComboBox.foreground", MaterialColors.BLACK);
table.put("ComboBox.border", MaterialBorders.roundedLineColorBorder(MaterialColors.COSMO_BLACK));
table.put("ComboBox.borderItems", BorderFactory.createEmptyBorder(1, 2, 0, 1));
table.put("ComboBox.buttonBackground", MaterialColors.WHITE);
table.put("ComboBox[button].border", BorderFactory.createLineBorder(MaterialColors.WHITE));
table.put("ComboBox.disabledBackground", MaterialColors.WHITE);
table.put("ComboBox.disabledForeground", MaterialColors.GRAY_900);
table.put("ComboBox.selectionBackground", MaterialColors.WHITE);
table.put("ComboBox.selectionForeground", Color.BLACK);
table.put("ComboBox.selectedInDropDownBackground", MaterialColors.COSMO_LIGTH_BLUE);
table.put("ComboBox.mouseHoverColor", MaterialColors.WHITE);
table.put("ComboBox.unfocusColor", MaterialColors.COSMO_BLACK);
table.put("ComboBox.focusColor", MaterialColors.LIGHT_BLUE_400);
table.put("ComboBox.mouseHoverEnabled", false);
table.put("Menu.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.REGULAR));
table.put("Menu.border", BorderFactory.createEmptyBorder(5, 5, 5, 5));
table.put("Menu.background", Color.WHITE);
table.put("Menu.foreground", Color.BLACK);
table.put("Menu.opaque", true);
table.put("Menu.selectionBackground", MaterialColors.GRAY_200);
table.put("Menu.selectionForeground", MaterialColors.BLACK);
table.put("Menu.disabledForeground", new Color(0, 0, 0, 100));
table.put("Menu.menuPopupOffsetY", 3);
table.put("Menu[MouseOver].enable", true); //TODO adding into master
table.put("MenuBar.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.BOLD));
table.put("MenuBar.background", Color.WHITE);
table.put("MenuBar.border", MaterialBorders.LIGHT_SHADOW_BORDER);
table.put("MenuBar.foreground", MaterialColors.BLACK);
table.put("MenuItem.disabledForeground", new Color(0, 0, 0, 100));
table.put("MenuItem.selectionBackground", MaterialColors.GRAY_200);
table.put("MenuItem.selectionForeground", Color.BLACK);
table.put("MenuItem.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.MEDIUM));
table.put("MenuItem.background", Color.WHITE);
table.put("MenuItem.foreground", Color.BLACK);
table.put("MenuItem.border", BorderFactory.createEmptyBorder(5, 0, 5, 0));
}
This is my app with my look and feel
This is my app when changing the look and feel
This is the code for changing the look and feel
public class DemoGUITest extends JFrame {
static {
try {
UIManager.setLookAndFeel(new MaterialLookAndFeel());
JDialog.setDefaultLookAndFeelDecorated(true);
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
private static final DemoGUITest SINGLETON = new DemoGUITest();
public void reloadUI(){
SwingUtilities.updateComponentTreeUI(this);
}
public void changeThemeWith(BasicLookAndFeel lookAndFeel){
try {
UIManager.setLookAndFeel(lookAndFeel);
this.reloadUI();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SINGLETON.initComponent();
}
});
}
}
This is a minimal example
Class main
import com.sun.java.swing.plaf.gtk.GTKLookAndFeel;
import mdlaf.utils.MaterialColors;
import mdlaf.utils.MaterialFontFactory;
import javax.swing.*;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.metal.MetalLookAndFeel;
import java.awt.*;
import java.awt.event.ActionEvent;
/**
* @author https://github.com/vincenzopalazzo
*/
public class MaterialMain extends JFrame {
public static MaterialMain SINGLETON = new MaterialMain();
static {
try {
UIManager.setLookAndFeel(new LookAndFeelTest());
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
public void init() {
JMenuBar menuBar = new JMenuBar();
JMenu file = new JMenu("File");
menuBar.add(file);
this.setJMenuBar(menuBar);
JPanel panel = new JPanel();
JButton changeTheme = new JButton();
changeTheme.setAction(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
try {
UIManager.setLookAndFeel(new GTKLookAndFeel());
} catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
SwingUtilities.updateComponentTreeUI(SINGLETON);
}
});
changeTheme.setText("Set GTK");
panel.add(changeTheme);
setTitle("Look and feel");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(630, 360);
add(panel);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SINGLETON.init();
}
});
}
public static class LookAndFeelTest extends MetalLookAndFeel{
@Override
protected void initClassDefaults(UIDefaults table) {
super.initClassDefaults(table);
table.put("MenuUI", MenuTestUI.class.getCanonicalName());
table.put("ButtonUI", JButtonUI.class.getCanonicalName());
}
@Override
protected void initComponentDefaults(UIDefaults table) {
super.initComponentDefaults(table);
//table.put("Menu.font", new FontUIResource(MaterialFontFactory.getInstance().getFont(MaterialFontFactory.REGULAR)));
table.put("Menu.border", new BorderUIResource(BorderFactory.createEmptyBorder(5, 5, 5, 5)));
table.put("Menu.background", (Color.ORANGE));
table.put("Menu.foreground", (Color.BLACK));
table.put("Menu.opaque", true);
table.put("Menu.selectionBackground", new ColorUIResource(Color.YELLOW));
table.put("Menu.selectionForeground", new ColorUIResource(Color.BLACK));
table.put("Menu.disabledForeground", new ColorUIResource(new Color(0, 0, 0, 100)));
table.put("Menu.menuPopupOffsetY", 3);
//table.put("MenuBar.font", MaterialFontFactory.getInstance().getFont(MaterialFontFactory.BOLD));
table.put("MenuBar.background", (Color.ORANGE));
//table.put("MenuBar.border", MaterialBorders.LIGHT_SHADOW_BORDER);
table.put("MenuBar.foreground", (Color.BLACK));
table.put("Button.highlight", Color.ORANGE);
table.put("Button.opaque", false);
table.put("Button.border", BorderFactory.createEmptyBorder(7, 17, 7, 17));
table.put("Button.background", Color.ORANGE);
table.put("Button.foreground", Color.BLACK);
table.put("Button.focusable", true);
table.put("Button[focus].color", Color.GREEN);
}
}
}
MenuUI
import mdlaf.animation.MaterialUIMovement;
import mdlaf.components.menu.MaterialMenuUI;
import mdlaf.utils.MaterialManagerListener;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuUI;
import java.awt.*;
/**
* @author https://github.com/vincenzopalazzo
*/
public class MenuTestUI extends BasicMenuUI {
public static ComponentUI createUI (JComponent c) {
return new MaterialMenuUI();
}
@Override
public void installUI (JComponent c) {
super.installUI (c);
JMenu menu = (JMenu) c;
menu.setFont (UIManager.getFont ("Menu.font"));
menu.setBorder (UIManager.getBorder ("Menu.border"));
menu.setBackground (UIManager.getColor ("Menu.background"));
menu.setForeground (UIManager.getColor ("Menu.foreground"));
menu.setOpaque (UIManager.getBoolean ("Menu.opaque"));
c.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@Override
public void uninstallUI(JComponent c) {
menuItem.setFont (null);
menuItem.setBackground (null);
menuItem.setForeground (null);
menuItem.setBorder (null);
menuItem.setCursor(null);
MaterialManagerListener.removeAllMaterialMouseListener(menuItem);
super.uninstallUI(menuItem);
}
}
ButtonUI
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
/**
* @author https://github.com/vincenzopalazzo
*/
public class JButtonUI extends BasicButtonUI {
public static final String UI_KEY = "ButtonUI";
public static ComponentUI createUI(final JComponent c) {
return new JButtonUI();
}
private AbstractButton button;
private Color foreground;
private Color background;
private Color disabledBackground;
private Color disabledForeground;
private Color defaultBackground;
private Color defaultForeground;
private Boolean isDefaultButton = null;
@Override
public void installUI(JComponent c) {
super.installUI(c);
AbstractButton button = (AbstractButton) c;
button.setOpaque(UIManager.getBoolean("Button.opaque"));
button.setBorder(UIManager.getBorder("Button.border"));
foreground = UIManager.getColor("Button.foreground");
background = UIManager.getColor("Button.background");
disabledBackground = UIManager.getColor("Button.disabledBackground");
disabledForeground = UIManager.getColor("Button.disabledForeground");
defaultBackground = UIManager.getColor("Button[Default].background");
defaultForeground = UIManager.getColor("Button[Default].foreground");
button.setBackground(background);
button.setForeground(foreground);
button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
button.setFocusable(UIManager.getBoolean("Button.focusable"));
this.button = button;
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
AbstractButton button = (AbstractButton) c;
button.setBorder(null);
foreground = null;
background = null;
disabledBackground = null;
disabledForeground = null;
defaultBackground = null;
defaultForeground = null;
button.setBackground(null);
button.setForeground(null);
button.setCursor(null);
}
@Override
public void paint(Graphics g, JComponent c) {
JButton b = (JButton) c;
if (b.isContentAreaFilled()) {
paintBackground(g, b);
}
if (isDefaultButton == null && b.isEnabled()) {
isDefaultButton = ((JButton) button).isDefaultButton();
if (isDefaultButton) {
paintStateButton(c, g);
}
}
super.paint(g, c);
}
private void paintBackground(Graphics g, JComponent c) {
Graphics2D graphics = (Graphics2D) g.create();
g.setColor(c.getBackground());
JButton b = (JButton) c;
if (!UIManager.getBoolean("Button[border].toAll") && (button.getIcon() != null)) {
g.fillRoundRect(0, 0, c.getWidth(), c.getHeight(), 7, 7);
} else {
g.fillRoundRect(0, 0, c.getWidth(), c.getHeight(), 7, 7);
if (isDefaultButton != null && isDefaultButton) {
g.setColor(UIManager.getColor("Button[Default].background"));
if(UIManager.getBoolean("Button[Default].shadowEnable")){
paintShadow(g, button);
}
return;
}
if(UIManager.getBoolean("Button[border].enable")){
paintBorderButton(graphics, b);
}
}
paintStateButton(c, g);
}
@Override
protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
// driveLine(g, (JButton) b);
paintFocusRing(g, (JButton) b);
//paintShadow(MaterialDrawingUtils.getAliasedGraphics(g), button);
}
@Override
public void update(Graphics g, JComponent c) {
super.update(g, c);
//c.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@Override
protected void paintButtonPressed(Graphics g, AbstractButton b) {
g.fillRoundRect(0, 0, b.getWidth(), b.getHeight(), 7, 7);
}
protected void paintFocusRing(Graphics g, JButton b) {
Stroke dashed = new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f, new float[]{0f, 3f}, 10.0f);
//Stroke dashed = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{9}, 0);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(dashed);
if (isDefaultButton) {
g2.setColor(UIManager.getColor("Button[Default][focus].color"));
} else {
g2.setColor(UIManager.getColor("Button[focus].color"));
}
g2.drawRoundRect(5, 5, b.getWidth() - 10, b.getHeight() - 10, 7, 7);
g2.dispose();
}
protected void paintShadow(Graphics g, JComponent c) {
int topOpacity = 80;
int pixels = UIManager.getInt("Button[Default].shadowPixel");
JButton b = (JButton) c;
int valueRed = 255;
int valueGreen = 255;
int valueBlue = 255;
for (int i = pixels; i >= 0; i--) {
if(valueBlue > 70){
valueRed -= 70;
valueGreen -= 70;
valueBlue -= 70;
}else{
valueBlue -= valueBlue;
valueGreen -= valueGreen;
valueRed -= valueRed;
}
Color result = new Color(valueRed, valueGreen, valueBlue, topOpacity);
g.setColor(result);
g.drawRoundRect(i, i, b.getWidth() - ((i * 2) + 1), b.getHeight() - ((i * 2) + 1), 7, 7);
}
}
protected void paintBorderButton(Graphics2D graphics, JButton b) {
graphics.setStroke(new BasicStroke(2f));
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int w = b.getWidth() - 1;
int h = b.getHeight() - 1;
int arc = 7;
graphics.setColor(UIManager.getColor("Button[border].color"));
graphics.drawRoundRect(0, 0, w, h, arc, arc);
}
protected void paintStateButton(JComponent component, Graphics graphics) {
if (component == null || graphics == null) {
throw new IllegalArgumentException("Input null");
}
JButton b = (JButton) component;
if (b.isEnabled() && (isDefaultButton != null && isDefaultButton) && !b.isSelected()) {
//MaterialManagerListener.removeAllMaterialMouseListener(b);
//b.addMouseListener(MaterialUIMovement.getMovement(b, MaterialColors.LIGHT_BLUE_100));
b.setBackground(defaultBackground);
b.setForeground(defaultForeground);
return;
}
if (!b.isEnabled()) {
b.setBackground(disabledBackground);
b.setForeground(disabledForeground);
return;
}
}
}
But this code does not reproduced the problem even though I copied my code; a demo with the error is here
I wanted to ask you if the problem is the one described above and especially if I used UIDefault badly
This could be an issue of your usage of L&F. All the resources, you put into the UIManager
(except the primitives), must be the instances of javax.swing.plaf.UIResource
intreface. Swing offers some predefined classes like ColorUIResource
, BorderUIResource
, IconUIResource
, etc., that you can use in your code.
Why is it required? This interface tells the next Look-n-Feel that this setting can be changed when it applies its settings.
Code example:
table.put("OptionPane.warningDialog.titlePane.shadow", new ColorUIResource(MaterialColors.COSMO_STRONG_GRAY));
table.put("FormattedTextField.border", new BorderUIResource(BorderFactory.createEmptyBorder(3, 5, 2, 5)));
table.put("List.font", new FontUIResource(MaterialFontFactory.getInstance().getFont(MaterialFontFactory.MEDIUM)));
Probably it would be better when your factories provide the resources in form of UIResource instances.