Актуализирайте стойностите на LookAndFeel в движение

Искам да мога да актуализирам атрибутите LookAndFeel на моя Swing GUI в движение. В този случай имам проста игра 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