Обновление значений LookAndFeel на лету

Я хочу иметь возможность обновлять атрибуты LookAndFeel моего графического интерфейса Swing на лету. В данном случае у меня есть простая игра Swing/Awt, которая начинается как Nimbus LookAndFeel. В разные моменты после запуска я хочу изменить (скажем) только одну деталь: цвет фона моего приложения.

Я могу изменить цвет фона, выполнив следующие действия:

for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
    if ("Nimbus".equals(info.getName())) {
        UIManager.setLookAndFeel(info.getClassName());
        UIManager.getLookAndFeelDefaults().put("Panel.background", Color.RED);
        SwingUtilities.updateComponentTreeUI(SomeGame.this);
        break;
    }
}

Это «работает» тем, что цвет фона приложения меняется правильно, и программа не падает. Но в командной строке получаю ошибку:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at javax.swing.plaf.synth.SynthLookAndFeel.paintRegion(SynthLookAndFeel.java:371)
    at javax.swing.plaf.synth.SynthLookAndFeel.update(SynthLookAndFeel.java:335)

Очевидно, что-то нулевое, но я не могу понять, что это такое и как это исправить. Должно быть что-то, чего я не понимаю. Я просмотрел другие вопросы StackOverflow о установка цветов фона в Nimbus и переопределение информации LookAndFeel после запуска.

  • Когда я вызываю getLookAndFeelDefaults(), нужно ли мне также указывать остальные значения по умолчанию?
  • Были ли изменения в том, как это работает между Java 1.6 и 1.7?

person theJollySin    schedule 06.02.2013    source источник


Ответы (1)


  • весь код для Java6, необходимо изменить импорт Nimbus для Java7

  • У Nimbus есть несколько сюрпризов, один из них в том, что можно (без грязных хаков, оставляю комментарии к этим хакам) поменять Background на JPanel только один раз

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Color;
import java.awt.AlphaComposite;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.EmptyBorder;

public class ButtonTest {

    private JFrame frame;
    private JPanel panel;
    private JButton opaqueButton1;
    private JButton opaqueButton2;
    private SoftJButton softButton1;
    private SoftJButton softButton2;
    private Timer alphaChanger;

    public void createAndShowGUI() {
        opaqueButton1 = new JButton("Opaque Button");
        opaqueButton2 = new JButton("Opaque Button");
        softButton1 = new SoftJButton("Transparent Button");
        softButton2 = new SoftJButton("Transparent Button");
        opaqueButton1.setBackground(Color.GREEN);
        softButton1.setBackground(Color.GREEN);
        panel = new JPanel();
        panel.setLayout(new java.awt.GridLayout(2, 2, 10, 10));
        panel.add(opaqueButton1);
        panel.add(softButton1);
        panel.add(opaqueButton2);
        panel.add(softButton2);
        panel.setBorder(new EmptyBorder(10, 10, 10, 10));
        frame = new JFrame();
        frame.add(panel);
        frame.setLocation(150, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        alphaChanger = new Timer(50, new ActionListener() {

            private float incrementer = -.03f;

            @Override
            public void actionPerformed(ActionEvent e) {
                float newAlpha = softButton1.getAlpha() + incrementer;
                if (newAlpha < 0) {
                    newAlpha = 0;
                    incrementer = -incrementer;
                } else if (newAlpha > 1f) {
                    newAlpha = 1f;
                    incrementer = -incrementer;
                }
                softButton1.setAlpha(newAlpha);
                softButton2.setAlpha(newAlpha);
            }
        });
        alphaChanger.start();
        Timer uiChanger = new Timer(3500, new ActionListener() {

            private final LookAndFeelInfo[] laf = UIManager.getInstalledLookAndFeels();
            private int index = 1;

            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    UIManager.setLookAndFeel(laf[index].getClassName());
                    if (laf[index].getClassName().equals("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel")) {
                        UIManager.getLookAndFeelDefaults().put("Panel.background", Color.orange);
                        SwingUtilities.updateComponentTreeUI(frame);
                    } else {
                        panel.setBackground(Color.yellow);
                        SwingUtilities.updateComponentTreeUI(frame);
                    }
                    opaqueButton1.setText(laf[index].getClassName());
                    softButton1.setText(laf[index].getClassName());
                    frame.pack();
                } catch (Exception exc) {
                    exc.printStackTrace();
                }
                index = (index + 1) % laf.length;
            }
        });
        uiChanger.start();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ButtonTest().createAndShowGUI();
            }
        });
    }

    private static class SoftJButton extends JButton {

        private static final JButton lafDeterminer = new JButton();
        private static final long serialVersionUID = 1L;
        private boolean rectangularLAF;
        private float alpha = 1f;

        SoftJButton() {
            this(null, null);
        }

        SoftJButton(String text) {
            this(text, null);
        }

        SoftJButton(String text, Icon icon) {
            super(text, icon);
            setOpaque(false);
            setFocusPainted(false);
        }

        public float getAlpha() {
            return alpha;
        }

        public void setAlpha(float alpha) {
            this.alpha = alpha;
            repaint();
        }

        @Override
        public void paintComponent(java.awt.Graphics g) {
            java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
            if (rectangularLAF && isBackgroundSet()) {
                Color c = getBackground();
                g2.setColor(c);
                g.fillRect(0, 0, getWidth(), getHeight());
            }
            super.paintComponent(g2);
        }

        @Override
        public void updateUI() {
            super.updateUI();
            lafDeterminer.updateUI();
            rectangularLAF = lafDeterminer.isOpaque();
        }
    }
}

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

public class NimbusTestButtonsBackground extends JFrame {

    private static final long serialVersionUID = 1L;
    private javax.swing.JButton button;

    public NimbusTestButtonsBackground() {
        button = new javax.swing.JButton();
        button.setText("Text");
        add(button);
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        this.pack();
        Timer t = new Timer(1000, new ActionListener() {

            private Random r = new Random();

            @Override
            public void actionPerformed(ActionEvent e) {
                Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
                try {
                    LookAndFeel lnf = UIManager.getLookAndFeel().getClass().newInstance();
                    UIDefaults uiDefaults = lnf.getDefaults();
                    uiDefaults.put("nimbusBase", c);
                    UIManager.getLookAndFeel().uninitialize();
                    UIManager.setLookAndFeel(lnf);
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }
                UIDefaults defaults = UIManager.getDefaults();
                defaults.put("Button.background", c);
                SwingUtilities.updateComponentTreeUI(button);
            }
        });
        t.start();
    }

    public static void main(String args[]) {
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            return;
        }

        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new NimbusTestButtonsBackground().setVisible(true);
            }
        });
    }
}
  • тогда я вижу (этот способ наиболее удобный, простой и т. д.) переопределение paintComponent для JPanel как лучший лучший способ

введите здесь описание изображениявведите описание изображения здесьвведите описание изображения здесь

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;

public class ChangePanelBackgroundNimbus {

    private JFrame frame = new JFrame();

    public ChangePanelBackgroundNimbus() {
        GradientPane pane = new GradientPane();
        pane.setLayout(new GridLayout(6, 4, 10, 10));
        for (int i = 1; i <= 24; i++) {
            pane.add(createButton(i));
        }
        pane.setOpaque(false);
        frame.add(pane);
        RepaintManager.setCurrentManager(new RepaintManager() {

            @Override
            public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
                Container con = c.getParent();
                while (con instanceof JComponent) {
                    if (!con.isVisible()) {
                        return;
                    }
                    if (con instanceof GradientPane) {
                        c = (JComponent) con;
                        x = 0;
                        y = 0;
                        w = con.getWidth();
                        h = con.getHeight();
                    }
                    con = con.getParent();
                }
                super.addDirtyRegion(c, x, y, w, h);
            }
        });
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        //frame.setSize(400, 300);
        frame.pack();
        frame.setVisible(true);
    }

    private JButton createButton(final int text) {
        JButton button = new JButton(Integer.toString(text));
        return button;
    }

    class GradientPane extends JPanel {

        private static final long serialVersionUID = 1L;
        private final int h = 150;
        private BufferedImage img = null;
        private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);

        public GradientPane() {
            paintBackGround(new Color(150, 250, 150));
            Timer t = new Timer(500, new ActionListener() {

                private Random r = new Random();

                @Override
                public void actionPerformed(ActionEvent e) {
                    paintBackGround(new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)));
                }
            });
            t.start();
        }

        public void paintBackGround(Color g) {
            Graphics2D g2 = shadow.createGraphics();
            g2.setPaint(g);
            g2.fillRect(0, 0, 1, h);
            g2.setComposite(AlphaComposite.DstIn);
            g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h, new Color(0.4f, 0.8f, 0.8f, 0.5f)));
            g2.fillRect(0, 0, 1, h);
            g2.dispose();
        }

        @Override
        public void paintComponent(Graphics g) {
            if (img == null || img.getWidth() != getWidth() || img.getHeight() != getHeight()) {
                img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
            }
            Graphics2D g2 = img.createGraphics();
            super.paintComponent(g2);
            Rectangle bounds = this.getVisibleRect();
            g2.scale(bounds.getWidth(), -1);
            g2.drawImage(shadow, bounds.x, -bounds.y - h, null);
            g2.scale(1, -1);
            g2.drawImage(shadow, bounds.x, bounds.y + bounds.height - h, null);
            g2.dispose();
            g.drawImage(img, 0, 0, null);
            repaint();
        }
    }

    public static void main(String[] args) {
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ChangePanelBackgroundNimbus ml = new ChangePanelBackgroundNimbus();
            }
        });
    }
}
person mKorbel    schedule 06.02.2013