您应该使用JPanel 而不是Canvas,所以让类Funktionier 扩展JPanel 而不是Canvas。
您应该重写方法 paintComponent() 而不是方法 paint()。在覆盖的paintComponent() 方法中,您需要做的第一件事是调用super.paintComponent()。
每次调用paintComponent(),您都需要绘制所有内容,因为每次调用paintComponent(),您都是从一个空白JPanel 开始的。所以不要只绘制“当前”图像。同时将你绘制的所有图像绘制到当前图像。
请参阅Painting in AWT and Swing 和Performing Custom Painting
编辑
代码后的解释。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
public class Funktionier extends JPanel implements DocumentListener, Runnable {
private static final long serialVersionUID = 4909941254467865823L;
private static final Image[] PNGS;
private JFrame frame;
private List<ImagLocn> imagesToDraw;
private Random rand;
static {
PNGS = new Image[26];
for (int i = 0; i < 26; i++) {
try {
PNGS[i] = ImageIO.read(new File("JAVA-" + (char) ('A' + i) + ".png"));
}
catch (IOException xIo) {
throw new RuntimeException(xIo);
}
}
}
public Funktionier(int width, int height) {
imagesToDraw = new ArrayList<>();
rand = new Random();
setPreferredSize(new Dimension(width, height));
}
@Override // javax.swing.event.DocumentListener
public void insertUpdate(DocumentEvent docEvent) {
if (docEvent.getLength() > 0) {
Document doc = docEvent.getDocument();
int length = doc.getLength();
try {
String text = doc.getText(0, length);
text = text.strip();
length = text.length();
String lastLetter = text.substring(length - 1, length);
int index = lastLetter.charAt(0) - 'A';
if (index >= 0 && index < PNGS.length) {
imagesToDraw.add(new ImagLocn(PNGS[index],
rand.nextInt(getWidth()),
rand.nextInt(getHeight())));
repaint();
}
}
catch (BadLocationException xBadLocation) {
throw new RuntimeException(xBadLocation);
}
}
}
@Override // javax.swing.event.DocumentListener
public void removeUpdate(DocumentEvent docEvent) {
// Do nothing.
}
@Override // javax.swing.event.DocumentListener
public void changedUpdate(DocumentEvent docEvent) {
// Do nothing.
}
@Override // java.lang.Runnable
public void run() {
showGui();
}
@Override // javax.swing.JComponent
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (ImagLocn il : imagesToDraw) {
g.drawImage(il.getImage(), il.getX(), il.getY(), null);
}
}
private JPanel createTextFieldPanel() {
JPanel textFieldPanel = new JPanel();
JTextField field = new JTextField(30);
Document doc = field.getDocument();
doc.addDocumentListener(this);
if (doc instanceof AbstractDocument) {
AbstractDocument absDoc = (AbstractDocument) doc;
absDoc.setDocumentFilter(new DocuFltr());
}
textFieldPanel.add(field);
return textFieldPanel;
}
private void showGui() {
frame = new JFrame("Deine Karte");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createTextFieldPanel(), BorderLayout.PAGE_START);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Funktionier(500, 500));
}
}
class DocuFltr extends DocumentFilter {
@Override
public void insertString(FilterBypass fb,
int offset,
String string,
AttributeSet attr) throws BadLocationException {
if (string.matches("^[A-Za-z]+$")) {
fb.insertString(offset, string.toUpperCase(), attr);
}
}
@Override
public void replace(FilterBypass fb,
int offset,
int length,
String text,
AttributeSet attrs) throws BadLocationException {
if (text.matches("^[A-Za-z]+$")) {
fb.replace(offset, length, text.toUpperCase(), attrs);
}
}
}
class ImagLocn {
private Image image;
private int x;
private int y;
public ImagLocn(Image img, int anX, int aY) {
image = img;
x = anX;
y = aY;
}
public Image getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
这是我运行上述代码时的样子。
- 请参阅Laying Out Components Within a Container。不要使用
setBounds() 将组件放置在屏幕上。使用布局管理器。 JFrame 的内容窗格的默认布局管理器是 BorderLayout。
- 我使用document filter 来确保只有字母表中的字母可以输入
JTextField。文档过滤器还将小写字母转换为大写。
- 我实现了document listener 而不是
KeyListener。在文档侦听器中,每次在JTextField 中输入另一个字母时,我都会将另一个图像添加到需要绘制的图像列表中。
- 正如我在原始答案中所写,我覆盖方法
paintComponent() 并始终绘制整个图像列表。
- 我把所有的PNG图片都放在了工作目录下,也就是
System.getProperty("user.dir")返回的值。我这样做只是为了让自己更轻松。你可以把它们放在你喜欢的任何地方。只需确保在代码中使用正确的文件路径即可。