【问题标题】:How to remain KeyListener Images on JFrame after pressing a new Key按下新键后如何在 JFrame 上保留 KeyListener 图像
【发布时间】:2021-02-15 05:53:48
【问题描述】:

我对 Java 完全陌生,我的项目是用键盘制作明信片生成器。 我现在的问题是,当按下新键时,我不知道如何使图像留在框架中。我确定我需要一个 ArrayList 但我不知道它在代码中的位置。 我会很感激任何帮助:)

public class Funktionier extends Canvas implements KeyListener {

private static final long serialVersionUID = 2576012469492443014L;
public JFrame frame;
private Image []pngs;
private int currentImage; 
private Random random;
private int x;
private int y;

public Funktionier(int width, int height)
{
    pngs = new Image[26]; 
    for (int i=0; i<26; i++) {
        try {
            pngs[i] = ImageIO.read(new File("./res/JAVA-"+(char) ('A'+i)+".png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    frame = new JFrame ();
    JTextField field = new JTextField (30); 
    field.setBounds(219, 10, 437, 20); 
    frame.add(field);
    
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("Deine Karte");
    frame.setResizable(false);
    frame.setSize(width, height);   
    field.addKeyListener(this);  

    frame.add(this);
    this.addKeyListener(this);
    this.requestFocus();
    frame.setVisible(true);
    //currentImage = 0;
    random = new Random (); 
    randomXY ();
}
public static void main (String[] args) {
    new Funktionier (874,620);
}
public void randomXY () {
    x= random.nextInt(getWidth()-130); 
    y= random.nextInt(getHeight()-110); 
}
public void paint (Graphics g)
{
    g.drawImage(pngs[currentImage],  x,  y,  pngs[currentImage].getWidth(null),  pngs[currentImage].getHeight(null),  null);
}
@Override
public void keyTyped(KeyEvent e) {  
}
@Override
public void keyPressed(KeyEvent e) {    
}
@Override
public void keyReleased(KeyEvent e) {   
    if(e.getKeyChar() < 'a' || e.getKeyChar() > 'z') return; 
    currentImage= e.getKeyChar()-'a' ;          
    randomXY ();    
    repaint (); 
}
}

【问题讨论】:

  • 您能否发布一个指向包含您的 26 张图片的 ZIP 文件的链接?

标签: java arrays swing arraylist keylistener


【解决方案1】:

您应该使用JPanel 而不是Canvas,所以让类Funktionier 扩展JPanel 而不是Canvas

您应该重写方法 paintComponent() 而不是方法 paint()。在覆盖的paintComponent() 方法中,您需要做的第一件事是调用super.paintComponent()

每次调用paintComponent(),您都需要绘制所有内容,因为每次调用paintComponent(),您都是从一个空白JPanel 开始的。所以不要只绘制“当前”图像。同时将你绘制的所有图像绘制到当前图像。

请参阅Painting in AWT and SwingPerforming 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;
    }
}

这是我运行上述代码时的样子。

  1. 请参阅Laying Out Components Within a Container。不要使用setBounds() 将组件放置在屏幕上。使用布局管理器。 JFrame 的内容窗格的默认布局管理器是 BorderLayout
  2. 我使用document filter 来确保只有字母表中的字母可以输入JTextField。文档过滤器还将小写字母转换为大写。
  3. 我实现了document listener 而不是KeyListener。在文档侦听器中,每次在JTextField 中输入另一个字母时,我都会将另一个图像添加到需要绘制的图像列表中。
  4. 正如我在原始答案中所写,我覆盖方法 paintComponent() 并始终绘制整个图像列表。
  5. 我把所有的PNG图片都放在了工作目录下,也就是System.getProperty("user.dir")返回的值。我这样做只是为了让自己更轻松。你可以把它们放在你喜欢的任何地方。只需确保在代码中使用正确的文件路径即可。

【讨论】:

  • 谢谢!不幸的是,如果我将 Canvas 更改为 JPanel,我的文本字段会不断消失。而且没有文本字段,我仍然只能看到当前图像。
  • 哇,非常感谢!解释的很清楚!
猜你喜欢
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 2022-12-20
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
  • 2023-02-18
  • 1970-01-01
相关资源
最近更新 更多