微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

按下新键后如何在JFrame上保留KeyListener图像

如何解决按下新键后如何在JFrame上保留KeyListener图像

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

解决方法

您应该使用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           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;
    }
}

这是运行上述代码时的外观。

Your card

  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")返回的值。我这样做只是为了让自己更轻松。您可以将它们放在您喜欢的任何位置。只需确保在代码中使用正确的文件路径即可。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。