试图在运行时更改JTextPane的背景,成功了,但有错误



所以我有一个JTextPane对象,它需要在运行时将其背景更改为特定图像的背景。我所拥有的似乎很有缺陷(JComboBox用于更改背景并调用repaintBackground()似乎不会在选择时自动关闭,等等),它还抛出了一个空指针,随着背景的变化,我不知道为什么。

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....

这是我的目标:

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());
    }
}

如有任何帮助,我们将不胜感激。

  1. paintComponent(this.getGraphics());-。您永远不应该显式调用paintComponent。而是调用repaint()

  2. super.paintComponent(g);应该在paintComponent方法的开始时调用,或者至少在使用Graphics上下文进行任何绘制之前调用。

  3. 不要使用paintComponent方法加载图像。一种选择是在Map<String, Image>中保留一个缓存。这样你就可以很容易地引用它们,而不必每次想要更改时都加载它们。总的来说,无论您是否决定缓存它们,都不是一个大问题。您可以在repaintBackground方法中加载它。

  4. 保留一个班级成员Image image;。这将是用于绘制的Image。你的repaintBackground,我会让它接受Image而不是字符串。传递的Image将是用于绘画的类成员Image image。如果您决定从该方法加载图像,您仍然可以让该方法接受String。

    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不应抛出RuntimeException

下面是一个完整的例子。我决定使用Map缓存。这取决于你想怎么做。有很多方法可以解决这个问题。

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();
            }
        });
    }
}

首先将图像初始化和绘制分开。将img加载移出绘画。也不要试图创建文件。如果JAR文件中的映像无法创建。

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);
}

最新更新