(JAVA)通过keylistener移动剪切区域

Posted

技术标签:

【中文标题】(JAVA)通过keylistener移动剪切区域【英文标题】:(JAVA) moving clipping area by keylistener 【发布时间】:2015-03-28 05:17:33 【问题描述】:

我的目标是使用箭头键一次将剪切区域移动 10 个像素。我在面板上得到了图像,剪切区域也在那里,但问题是剪切区域不会移动。这是我的代码,我希望了解它有什么问题。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class clipping_area extends JFrame
    clipping_area()
        setTitle("OpenChallenge");
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500,500);
        add(new panelOC());
    
    class panelOC extends JPanel
        int xAxis=0;
        int yAxis=0;
        public void paintComponent(Graphics g)
            super.paintComponent(g);
            Image img=(new ImageIcon("images/image1.jpg")).getImage();
            g.setClip(100+10*xAxis,100+10*yAxis,50,50);
            g.drawImage(img,0,0,getWidth(),getHeight(),this);
        
        panelOC()
            requestFocus();
            addKeyListener(new KeyAdapter()
                public void keyPressed(KeyEvent KE)
                    if(KE.getKeyCode()==KeyEvent.VK_UP)
                        yAxis-=1;
                        repaint();
                    
                    else if(KE.getKeyCode()==KeyEvent.VK_DOWN)
                        yAxis+=1;
                        repaint();
                    
                    else if(KE.getKeyCode()==KeyEvent.VK_LEFT)
                        xAxis-=1;
                        repaint();
                    
                    else if(KE.getKeyCode()==KeyEvent.VK_RIGHT)
                        xAxis+=1;
                        repaint();
                    
                
            );
        
    
    public static void main(String[] args)
        new clipping_area();
    

【问题讨论】:

欢迎来到Java,你不妨阅读一下Code Conventions for the Java TM Programming Language,它会让人们更容易阅读你的代码,也让你更容易阅读其他人 不要从任何paint 方法中加载资源,绘制方法应该是绘制,这样加载资源可能会减慢绘制过程 【参考方案1】:

KeyListener 在重点领域确实很痛苦。如果它附加到的组件是不可聚焦的并且有键盘焦点,它不会触发事件,这就是它的设计方式。相反,请使用专为解决此问题而设计的 Key Bindings API。

详情请见How to Use Key Bindings

小心修改Graphics 上下文的clipGraphics 上下文是共享资源,这意味着它将过去给其他组件。如果您不小心,您也可以将剪辑的大小调整到超出组件范围的范围,从而导致一些奇怪的图形故障,就我个人而言,我远离它。

如果您改用ImageIO.read,您可以获得对BufferedImage 的引用并使用getSubImage 来“伪造”它

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import static javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ClippingArea extends JFrame 

    ClippingArea() 
        setTitle("OpenChallenge");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(new PanelOC());
        pack();
        setVisible(true);
    

    class PanelOC extends JPanel 

        int xAxis = 0;
        int yAxis = 0;
        private BufferedImage img;

        @Override
        public Dimension getPreferredSize() 
            return new Dimension(500, 500);
        

        @Override
        protected void paintComponent(Graphics g) 
            super.paintComponent(g);
            if (img != null) 

                int width = 50;
                if (xAxis + width > img.getWidth()) 
                    width = img.getWidth() - xAxis;
                
                int height = 50;
                if (yAxis + height > img.getHeight()) 
                    height = img.getHeight() - yAxis;
                

                if (width > 0 && height > 0) 

                    BufferedImage subImage = img.getSubimage(xAxis, yAxis, width, height);
                    g.drawImage(subImage, xAxis, yAxis, this);

                

            

        

        protected void registerKeyBinding(String name, KeyStroke keyStroke, Action action) 
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(keyStroke, name);
            am.put(name, action);
        

        public PanelOC() 

            try 
                img = ImageIO.read(new File("C:\\hold\\thumbnails\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
             catch (IOException ex) 
                ex.printStackTrace();
            

            registerKeyBinding("moveClip.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new YKeyAction(-10));
            registerKeyBinding("moveClip.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new YKeyAction(10));
            registerKeyBinding("moveClip.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), new XKeyAction(-10));
            registerKeyBinding("moveClip.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), new XKeyAction(10));
        

        public class XKeyAction extends AbstractAction 

            private int delta;

            public XKeyAction(int delta) 
                this.delta = delta;
            

            @Override
            public void actionPerformed(ActionEvent e) 
                xAxis += delta;
                if (yAxis > getWidth()) 
                    yAxis = getWidth() - 50;
                 else if (yAxis < 0) 
                    yAxis = 0;
                
                repaint();
            

        

        public class YKeyAction extends AbstractAction 

            private int delta;

            public YKeyAction(int delta) 
                this.delta = delta;
            

            @Override
            public void actionPerformed(ActionEvent e) 
                yAxis += delta;
                if (yAxis > getHeight()) 
                    yAxis = getHeight() - 50;
                 else if (yAxis < 0) 
                    yAxis = 0;
                
                repaint();
            

        
    

    public static void main(String[] args) 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                 catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                    ex.printStackTrace();
                

                ClippingArea ca = new ClippingArea();
            
        );
    

查看Reading/Loading an Image了解更多详情

您还应该在事件调度线程的上下文中创建和修改您的 UI,有关更多详细信息,请参阅 Initial Threads

【讨论】:

【参考方案2】:

使用 AWTEventListener 代替面板上的按键监听器(它将抓取特定类型的所有事件

java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
    toolkit.addAWTEventListener(new AWTEventListener() 
        @Override
        public void eventDispatched(AWTEvent ae) 
            if (ae instanceof KeyEvent) 
                KeyEvent KE = (KeyEvent) ae;
                if (KE.getID() == KeyEvent.KEY_PRESSED) 
                    switch(KE.getKeyCode()) 
                        case KeyEvent.VK_UP:
                            yAxis -= 1;
                            break;
                        case KeyEvent.VK_DOWN:
                            yAxis += 1;
                            break;
                        case KeyEvent.VK_LEFT:
                            xAxis -= 1;
                            break;
                        case KeyEvent.VK_RIGHT:
                            xAxis += 1;
                            break;
                    
                    repaint();
                
            
        
    , AWTEvent.KEY_EVENT_MASK);

第二次编辑时,我用 switch 替换了你的 if 语句(它读起来更清晰,以后也更容易修改。

【讨论】:

只有给定的 java 应用程序有焦点,并且通过代码阅读,他似乎试图在单个组件应用程序中强制焦点。我假设他的意图是收集所有关键事件。 如果 OP 添加文本组件会发生什么?你会从中挑选出关键事件吗?菜单呢?使用全局监听器有它的用处,但这真的不是其中之一,尤其是当已经有一个可用的 API 可以简单轻松地解决问题时......只是说...... 虽然它可以简单轻松地为我们任何人解决问题,但您可以从一英里外看到这个人对 java 相当陌生,并且查看代码甚至没有启动 IDE 和跑步,并不完全是要指导他建立 8 个班级并将他扔到众所周知的深渊。 更有理由为 OP 提供“正确”答案,而不仅仅是“满足”当下的答案 - 毕竟,您不希望其他人必须清理你已经创建了... 感谢您的帮助。正如你所说,我对此很陌生。我认为我的 JPanel 没有得到它需要的焦点。(如果 keyPressed 工作但它不会打印任何东西,我已经通过让它在控制台上打印一些东西来测试它。)我尝试了 setFocusable = true 和 requestFocusInWindow。

以上是关于(JAVA)通过keylistener移动剪切区域的主要内容,如果未能解决你的问题,请参考以下文章

Java KeyListener 口吃

如何在java中正确使用keylistener

KeyListener 多久检查一次键盘输入? (Java 图形用户界面)

Java反向剪切区域?

Fabric.js 画布上的多个剪切区域

怎样使用java编程实现文件的剪切/移动