简体   繁体   English

(JAVA)通过侦听器移动剪切区域

[英](JAVA) moving clipping area by keylistener

My goal is moving clipping area 10 pixels at a time using arrow keys. 我的目标是使用箭头键一次将剪切区域移动10个像素。 I got the image on the panel and the clipping area is there too, but the thing is that the clipping area won't move. 我在面板上看到了图像,剪切区域也在那里,但是问题是剪切区域不会移动。 Here is my code, and I hope to learn what's wrong with it. 这是我的代码,我希望了解它的问题。

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

KeyListener is a real pain in the, well, focus area. 在重点领域, KeyListener确实是一个KeyListener If the component it is attached to is not focusable AND has keyboard focus, it won't trigger events, that's the way it's designed. 如果它所连接的组件不可聚焦并且具有键盘焦点,则它不会触发事件,这就是它的设计方式。 Instead, use the Key Bindings API which has been designed to overcome this. 相反,请使用旨在解决此问题的Key Bindings API。

See How to Use Key Bindings for more details 有关更多详细信息,请参见如何使用键绑定

Be wary of modifying the clip of a Graphics context, a Graphics context is shared resource, meaning that it will be past to other components. 注意修改Graphics上下文的clip时要小心, Graphics上下文是共享资源,这意味着它将被传递给其他组件。 You could also, if you're not careful, size the clip in such away as to paint beyond the range of the component, causing some weird graphics glitches, personally, I stay away from it. 如果您不小心,还可以调整剪辑的大小,以使其超出组件的范围进行绘制,从而导致一些奇怪的图形故障,就我个人而言,我远离它。

If you use ImageIO.read instead, you can get a reference to a BufferedImage and use getSubImage to "fake" it instead 如果改用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();
            }
        });
    }
}

Take a look at Reading/Loading an Image for more details 看看阅读/加载图像的更多细节

You should also be creating and modiying your UI from within the context of the Event Dispatching Thread, see Initial Threads for more details 您还应该在事件调度线程的上下文中创建和修改UI,有关更多详细信息,请参见初始线程

instead of using a keylistener on a panel use a AWTEventListener (which will grab all events of a particular type 而不是在面板上使用键侦听器,而是使用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);

And a second edit, I replaced your if statements with a switch ( its significantly cleaner to read and easier to modify later. 再进行第二次编辑,我将您的if语句替换为一个开关(该开关更清晰易读,以后更容易修改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM