所以我有一个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());
}
}
如有任何帮助,我们将不胜感激。
-
paintComponent(this.getGraphics());
-否。您永远不应该显式调用paintComponent
。而是调用repaint()
。 -
super.paintComponent(g);
应该在paintComponent
方法的开始时调用,或者至少在使用Graphics
上下文进行任何绘制之前调用。 -
不要使用
paintComponent
方法加载图像。一种选择是在Map<String, Image>
中保留一个缓存。这样你就可以很容易地引用它们,而不必每次想要更改时都加载它们。总的来说,无论您是否决定缓存它们,都不是一个大问题。您可以在repaintBackground
方法中加载它。 -
保留一个班级成员
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); } }
-
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);
}