简体   繁体   中英

Trying to change background of JTextPane during runtime, succeeding but with errors

So I have a JTextPane object that needs to change it's background to that of a specific image during runtime. What I have seems to be quite buggy ( JComboBox used to change the background and call repaintBackground() doesn't seem to autoclose on selection, etc), it also throws a nullpointer and I have no clue why as the background changes.

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.text.BoxView.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI$RootView.paint(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paintSafely(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.paint(Unknown Source)
at javax.swing.plaf.synth.SynthEditorPaneUI.paint(Unknown Source)
at javax.swing.plaf.synth.SynthEditorPaneUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
etc etc etc....

This is my object:

public class PreviewPane extends JTextPane  {
    private String _name = "bg3";   

    public PreviewPane() {
        super();
        setOpaque(false);
        StyledDocument document = this.getStyledDocument();
        SimpleAttributeSet center = new SimpleAttributeSet();
        StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
        document.setParagraphAttributes(0, document.getLength(), center, false);
    }

    @Override
    protected void paintComponent(Graphics g)  throws RuntimeException{
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());

        BufferedImage img = null;

            try {
                img = ImageIO.read(new File(getClass().getResource("/icons/"+_name+".png").toURI()));
            } catch (IOException | URISyntaxException e) {
                // TODO Auto-generated catch block
                //e.printStackTrace();
            }

         g.drawImage(img, 0, 0, this);


        super.paintComponent(g);
    }

    public void repaintBackground(String bgName){

        _name = bgName;

        paintComponent(this.getGraphics());

    }

}

Any help would be appreciated.

  1. paintComponent(this.getGraphics()); - NO . You should never have to explicitly call paintComponent . Instead call repaint() .

  2. super.paintComponent(g); should be called at the beginning of the paintComponent method, or at least before you do any painting in with the Graphics context.

  3. Don't load your images in the paintComponent method. One option is to keep a cache in a Map<String, Image> . That way you can easily refer to them, without having to load them each time you want to change. Overall it's not that huge of an issue, whether you decide to cache them or not. You can just load it in the repaintBackground method.

  4. Keep a class member Image image; . This will be the Image you use to paint. Your repaintBackground , I would have it accept an Image instead of a String. The Image you pass will the class member Image image that is used for the painting. You could still have the method accept a String, if you decide to load the image from that method.

     classs MyPanel extends JPanel { Image image; public void repaintBackground(Image image) { this.image = image; repaint(); } protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image); } } 
  5. paintComponent should not throw a RuntimeException

Here's a complete example. I decided to go with the Map cache. It up to you how you want to do it. There's many ways you can handle this.

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class ImageChangeDemo {

    private ImagePanel imagePanel = new ImagePanel();

    public ImageChangeDemo() {
        JFrame frame = new JFrame();
        frame.add(imagePanel);
        frame.add(createCombo(), BorderLayout.PAGE_START);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JComboBox createCombo() {
        String[] items = {
            ImagePanel.DIRECTORY,
            ImagePanel.COMPUTER,
            ImagePanel.FILE,
            ImagePanel.FLOPPY,
            ImagePanel.HARD_DRIVE
        };
        JComboBox comboBox = new JComboBox(items);
        comboBox.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                imagePanel.repaintBackground(comboBox.getSelectedItem().toString());
            }
        });
        return comboBox;
    }

    private class ImagePanel extends JPanel {
        public static final String DIRECTORY = "directory";
        public static final String FILE = "file";
        public static final String COMPUTER = "computer";
        public static final String HARD_DRIVE = "harddrive";
        public static final String FLOPPY = "floppy";

        Map<String, Image> images = new HashMap<>();

        private Image currentImage;

        public ImagePanel() {
            initImageMap();
            repaintBackground(DIRECTORY);
        }

        private void initImageMap() {
            ImageIcon dirIcon = (ImageIcon)UIManager.getIcon("FileView.directoryIcon");
            ImageIcon fileIcon =(ImageIcon)UIManager.getIcon("FileView.fileIcon");
            ImageIcon compIcon = (ImageIcon)UIManager.getIcon("FileView.computerIcon");
            ImageIcon hdIcon = (ImageIcon)UIManager.getIcon("FileView.hardDriveIcon");
            ImageIcon flopIcon = (ImageIcon)UIManager.getIcon("FileView.floppyDriveIcon");
            images.put(DIRECTORY, dirIcon.getImage());
            images.put(FILE, fileIcon.getImage());
            images.put(COMPUTER, compIcon.getImage());
            images.put(HARD_DRIVE, hdIcon.getImage());
            images.put(FLOPPY, flopIcon.getImage());
        }

        protected void repaintBackground(String key) {
            currentImage = images.get(key);
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(currentImage, 0, 0, getWidth(), getHeight(), this);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(150, 150);
        }
    }

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

First of all separate image initilizing and drawing. Move the img loading out of paint. Also don't try to create file. If the image in a JAR file could not be created.

public PreviewPane() {
    super();
    setOpaque(false);
    StyledDocument document = this.getStyledDocument();
    SimpleAttributeSet center = new SimpleAttributeSet();
    StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
    document.setParagraphAttributes(0, document.getLength(), center, false);
}

BufferedImage img = null;

private void initImg() {
    if( img==null) {
        img = ImageIO.read(getClass().getResourceAsStream("/icons/"+_name+".png")));
//process missing img here
    }
}

@Override
protected void paintComponent(Graphics g)  throws RuntimeException{
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, getWidth(), getHeight());
    initImg();

    BufferedImage img = null;

     g.drawImage(img, 0, 0, this);


    super.paintComponent(g);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM