简体   繁体   English

在Java中使用Keylistener用箭头键在GUI中绘制线条

[英]Drawing lines in GUI with arrow keys using keylistener in Java

I am working on a keylistener exercise for my java class, but have been stuck for the past week. 我正在为Java类进行Keylistener练习,但过去一周一直处于停滞状态。 I appreciate any helpful suggestions. 我感谢任何有用的建议。 The exercise is: 练习是:

"Write a program that draws line segments using the arrow keys. The line starts from the center of the frame and draws toward east, north, west, or south when the right-arrow key, up-arrow key, left-arrow key, or down-arrow key is clicked." “编写一个使用箭头键绘制线段的程序。当使用右箭头键,上箭头键,左箭头键时,该线从框架的中心开始向东,北,西或南方向绘制,或单击向下箭头键。”

Through debugging I figured out that the KeyListener works to the point of getting to drawComponent(Graphics g), but it only draws when I press down or right and that only works the first couple times. 通过调试,我发现KeyListener可以使用到drawComponent(Graphics g)的程度,但是只有当我按下或向右按下时它才绘制,并且仅在前两次起作用。 Here is my code: 这是我的代码:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class EventProgrammingExercise8 extends JFrame {

    JPanel contentPane;
    LinePanel lines;
    public static final int SIZE_OF_FRAME = 500;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    EventProgrammingExercise8 frame = new EventProgrammingExercise8();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public EventProgrammingExercise8() {
        setTitle("EventExercise8");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(SIZE_OF_FRAME, SIZE_OF_FRAME);
        contentPane = new JPanel();
        lines = new LinePanel();
        contentPane.add(lines);
        setContentPane(contentPane);
        contentPane.setOpaque(true);
        lines.setOpaque(true);

        lines.setFocusable(true);
        lines.addKeyListener(new ArrowListener());
    }

    private class LinePanel extends JPanel {

        private int x;
        private int y;
        private int x2;
        private int y2;

        public LinePanel() {
            x = getWidth() / 2;
            y = getHeight() / 2;
            x2 = x;
            y2 = y;
        }

        protected void paintComponent(Graphics g) {
            g.drawLine(x, y, x2, y2);
            x = x2;
            y = y2;
        }

        public void drawEast() {
            x2 += 5;
            repaint();
        }

        public void drawWest() {
            x2 -= 5;
            repaint();
        }

        public void drawNorth() {
            y2 -= 5;
            repaint();
        }

        public void drawSouth() {
            y2 += 5;
            repaint();
        }

    }

    private class ArrowListener extends KeyAdapter {

        public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_RIGHT) {
                lines.drawEast();
            } else if (key == KeyEvent.VK_LEFT) {
                lines.drawWest();
            } else if (key == KeyEvent.VK_UP) {
                lines.drawNorth();
            } else {
                lines.drawSouth();
            }
        }

    }

}

Thanks. 谢谢。

A few things jump out at me... 有几件事突然出现在我身上...

public LinePanel() {
    x = getWidth() / 2;
    y = getHeight() / 2;

This will be an issue, because at the time you construct the class, it's size is 0x0 这将是一个问题,因为在构造类时,它的大小为0x0

Apart from the fact that you haven't called super.paintComponent which breaks the paint chain, you seem to think that painting is accumaltive... 除了您没有调用super.paintComponent破坏了画图链之外,您似乎还认为绘画是蓄意的...

protected void paintComponent(Graphics g) {
    g.drawLine(x, y, x2, y2);
    x = x2;
    y = y2;
}

Painting in Swing is destructive. Swing中的绘画具有破坏性。 That is, you are expected to erase to the Graphics context and rebuild the output from scratch. 也就是说,您应该擦除到Graphics上下文并从头开始重建输出。 The job paintComponent is to clear the Graphics context ready for painting, but you've not called super.paintComponent , breaking the paint chain and opening yourself up to a number of very ugly paint artifacts paintComponent的工作是清除可用于绘画的Graphics上下文,但是您尚未调用super.paintComponent ,它断开了绘画链,使自己对许多非常丑陋的绘画工件super.paintComponent

Calling setSize(SIZE_OF_FRAME, SIZE_OF_FRAME); 调用setSize(SIZE_OF_FRAME, SIZE_OF_FRAME); on a frame is dangerous, as it makes no guarantee about the frames border insets, which will reduce the viewable area available to you. 框架上的危险是危险的,因为它不能保证框架的边框插图,这会减少您可用的可视区域。

This.... 这个....

contentPane = new JPanel(); 
lines = new LinePanel();
contentPane.add(lines);
setContentPane(contentPane);

Is not required, it just adds clutter to your code. 不需要,它只会使您的代码混乱。 It's also a good hint as to what is going wrong with your code. 这对于代码出了什么问题也是一个很好的提示。

JPanel uses a FlowLayout by default. JPanel默认使用FlowLayout A FlowLayout uses the component's preferred size to determine how best to layout the components. FlowLayout使用组件的首选大小来确定如何最好地布局组件。 The default preferred size of a component is 0x0 组件的默认首选大小为0x0

You could use... 你可以用...

lines = new LinePanel();
add(lines);

instead or set the contentPane to use a BorderLayout which will help... 而是将contentPane设置为使用BorderLayout ,这将有助于...

Try adding lines.setBorder(new LineBorder(Color.RED)); 尝试添加lines.setBorder(new LineBorder(Color.RED)); add see what you get... 添加看看你得到...

Oddly, during my testing, your KeyListener worked fine... 奇怪的是,在我的测试过程中,您的KeyListener运行良好...

Basically... 基本上...

  • Override the getPreferredSize method of the LinePanel and return the size of the panel you would like to use. 覆盖LinePanelgetPreferredSize方法,并返回要使用的面板的大小。
  • Use a java.util.List to maintain a list of Point s that need to be painted. 使用java.util.List维护需要绘制的Point列表。
  • In you paintComponent method, use the Point List to actually render you lines. paintComponent方法中,使用“ Point List实际渲染线条。 This will be a bit tricky, as you need two points and the List may contain an odd number of points, but's doable. 这将有些棘手,因为您需要两个点,并且List可能包含奇数个点,但是是可行的。
  • Calculate the start Point either by using the preferred size or some other means (like using a ComponentListener and monitoring the componentResized method. This becomes tricky as your component may be resized a number of times when it is first created and released to the screen and you will want to ignore future events once you have your first point) 计算开始Point通过使用优选的大小或某些其它手段(如使用任一ComponentListener和监测componentResized方法。这变得棘手,因为您的部件可以被调整大小的次数被首先创建时并释放到屏幕和你一旦掌握了第一点,就会想忽略未来的事件)

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

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