【问题标题】:Add a keyListener inside a loop ? Is it possible?在循环中添加 keyListener ?可能吗?
【发布时间】:2013-03-23 15:23:14
【问题描述】:

我有输入此代码的侦听器:

        someBoolean = true;
        case FILL_POLYGON:      
        {
            if (greenLightForFilling == true)
            {
                while (someBoolean)
                {
                    fillPressed = true;
                    fillPolygon(polyFiller);
                }

            }
            break;

        }  // end FILL_POLYGON

当我点击 f 时。

是否可以在 while 循环中添加 另一个 侦听器,所以当 用户再次点击fsomeBoolean 会得到false 吗?

请注意,我已经有一个用于输入开关盒的按键监听器。

问候

编辑 - 相关代码:

public class DrawPolygons
{
    public static void main (String[] args) throws FileNotFoundException
    {
        // attaching the menu to the frame
        final JFrame frame = new JFrame("Draw polygons");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new DrawingPanel());
        frame.pack();
        frame.setVisible(true);
    }

}


/**
 * Main class
 * @author X2
 *
 */
class DrawingPanel extends JPanel implements MouseListener, MouseMotionListener ,KeyListener
{
    /**
     *    private variables
     */

    // dimensions of the window
    private static final long serialVersionUID = 1L;
    private static final Dimension MIN_DIM = new Dimension(300, 300);
    private static final Dimension PREF_DIM = new Dimension(500, 500);


    // Hot-keys hit by the user - used for keyboard listening
    private static final char FILL_POLYGON = 'F';
    private static final char SAVE_POLYGONS = 'S';
    private static final char LOAD_POLYGONS = 'L';
    private static final char FILL_POLYGON_LOWERCASE = 'f';
    private static final char SAVE_POLYGONS_LOWERCASE = 's';
    private static final char LOAD_POLYGONS_LOWERCASE = 'l';
    private static final String SPACE = " ";


    // boolean flags
    private boolean greenLightForFilling = false;
    private boolean polygonDone = false;
    private boolean loading = false;
    private boolean loading2 = false;
    private boolean fillPressed = false;

    // data structures

    // The dummy point tracking the mouse
    private final Point trackPoint = new Point();                    

    // The list of points making up a polygon
    private ArrayList<Point> points = new ArrayList<Point>();   

    // holds edges of current polygon
    private ArrayList<Edge> edges = new ArrayList<Edge>();  

    // array-list of vertices
    private ArrayList<Point> vertices = new ArrayList<Point>();      

    // all the polygons
    private ArrayList<Polygon> polygons = new ArrayList<Polygon>();  

    // count the vertices
    private int verticesCounter = 0;

    // hold polygon vertices for the polygon-filling
    private Vector<Point> polygon = new Vector<Point>();

    private ArrayList<Point> bigVerticesList= new ArrayList<Point>();

    static int counter = 0;
    /**
     * Setting the dimensions of the window
     */
    public Dimension getMinimumSize() { return MIN_DIM; }

    public Dimension getPreferredSize() { return PREF_DIM; }

    /**
     *  The constructor
     */
    DrawingPanel()
    {
        super();
        addMouseListener(this);
        addMouseMotionListener(this);
        addKeyListener(this);
        setFocusable(true);
        requestFocusInWindow();
    }



    /**
     *  The drawing itself 
     */
    public void paintComponent(Graphics g)
    {

        super.paintComponent(g);

        // draw previous polygons

        if (this.polygons.size() > 0)
            drawPreviousPolygons(g);


        int numPoints = points.size();
        if (numPoints == 0)
            return; // nothing to draw


        Point prevPoint = points.get(0);

        // draw polygon
        Iterator<Point> it = points.iterator();
        while (it.hasNext())
        {
            Point curPoint = it.next();
            draw(g, prevPoint, curPoint);           
            prevPoint = curPoint;
        }

        // now draw tracking line or complete the polygon
        if (polygonDone == true)
        {
            Point point0 = points.get(0);       // grab the starting point (x,y) 

            // draw the last edge between the starting point & the last point 
            draw(g, prevPoint, point0);

        }

        else  // polygonDone == false
            draw(g, prevPoint, trackPoint); 

    }



    /**
     * MouseListener interface 
     */
    public void mouseClicked(MouseEvent evt)
    {
        int x = evt.getX();
        int y = evt.getY();

        if (polygonDone == false)
        {
            Point p = new Point(x,y);       // new point 
            vertices.add(p);                // add to vertices list 
            this.verticesCounter++; 
        }


        if (verticesCounter > 1)    // create a new edge 
        {
            int verSize = vertices.size();      // grab number of vertices
            Point p1 = vertices.get(verSize - 1); // grab the last vertex 
            Point p2 = vertices.get(verSize - 2); // grab the one before last vertex 

            // create the current edge between the two points P1 and P2
            Edge currentEdge = new Edge(p1,p2);

            // add the edge to the edges list 
            if (polygonDone == false)
                this.edges.add(currentEdge);

        }

        switch (evt.getClickCount())
        {
            case 1: // single-click
                if (polygonDone == true)
                {
                    /**
                     * remove all the entries from the edges list - preparing for the next polygon  
                     */


                    // first add the last edge between the final vertex and the first vertex
                    Point p1 = null ,p2 = null;
                    if (!loading)
                    {
                        p1 = this.vertices.get(0);  // grab 1st vertex 
                        int verSize = vertices.size();                      
                        p2 = vertices.get(verSize - 1);     // grab last vertex 
                        // create the last edge between the final point & the first point 
                        Edge currentEdge = new Edge(p1,p2);

                        // add the last edge to the edges list 
                        this.edges.add(currentEdge);        
                    }


                    if (loading)
                        loading = false;

                    // create the new polygon structure with the edges 
                    Polygon poly = new Polygon(this.edges , this.vertices);

                    // add the polygon to the polygons array 
                    this.polygons.add(poly);

                    // reset edges ,reset points , reset vertices-counter , reset vertices  

                    greenLightForFilling = true;

                    verticesCounter = 0;
                    edges.clear();
                    points.clear();  
                    vertices.clear();
                    polygonDone = false;
                    repaint();
                    break;

                }
                points.add(new Point(x, y));
                repaint();
                break;

            case 2: // double-click
                polygonDone = true;
                points.add(new Point(x, y));
                repaint();
                break;

            default: // ignore anything else
                break;
        }
    }






    /**
     * MouseMotionListener interface 
     */
    public void mouseMoved(MouseEvent evt)
    {
        trackPoint.x = evt.getX();
        trackPoint.y = evt.getY();
        repaint();
    }



    /**
     * draw points and lines 
     * @param g
     * @param p1
     * @param p2
     */
    private void draw(Graphics g, Point p1, Point p2)
    {
        int x1 = p1.x;
        int y1 = p1.y;

        int x2 = p2.x;
        int y2 = p2.y;

        // draw the line
        g.setColor(Color.green.darker());
        g.drawLine(x1 + 3, y1 + 3, x2 + 3, y2 + 3);

        // now just paint the edge between those two points
        g.setColor(Color.green);
        g.fillOval(x1, y1, 8, 8);

        g.setColor(Color.black);
        g.fillOval(x2, y2, 8, 8);

        greenLightForFilling = false;       
    }





    /**
     * Run on the arrayList of the Polygons , and draw the previous polygons 
     * that we already made 
     * @param g
     */
    private void drawPreviousPolygons(Graphics g) 
    {
        int i = 0;

        while (i < this.polygons.size())
        {
            Polygon currentPoly = polygons.get(i);  // grab current polygon
            int j = 0; 

            ArrayList<Edge> edges = currentPoly.getPolygonEdges();


            // draw the edges of the polygon
            while (j < edges.size()) // run on all the edges of the polygon
            {
                Edge edgeCurrent = edges.get(j);        // grab current edge

                // drawing the edge 

                // now draw it - grab the two points that create the edge
                int x1 = edgeCurrent.getX1();
                int y1 = edgeCurrent.getY1();

                int x2 = edgeCurrent.getX2();
                int y2 = edgeCurrent.getY2();

                // draw the line first so that the points appear on top of the line ends, not below
                g.setColor(Color.green.darker());
                g.drawLine(x1 + 3, y1 + 3, x2 + 3, y2 + 3);

                // now just paint the edge between those two points
                g.setColor(Color.green);
                g.fillOval(x1, y1, 8, 8);

                g.setColor(Color.black);
                g.fillOval(x2, y2, 8, 8);

                // proceed to next edge 

                j++; 


            }

            i++;    // next polygon

        }


    }


    @Override
    public void keyTyped(KeyEvent keyEvent) 
    {
        PolygonFiller polyFiller = new PolygonFiller();
        char key = keyEvent.getKeyChar();


        switch(key)
        {
            /**
             *  Fill the polygons 
             */
            case FILL_POLYGON:      
            {
                if (greenLightForFilling == true)
                {
                    while (true)
                    {
                        fillPolygon(polyFiller);
                    }

                }
                break;

            }  // end FILL_POLYGON


            case FILL_POLYGON_LOWERCASE:
            {
                if (greenLightForFilling == true)
                {
                    fillPolygon(polyFiller);
                }
                break;              

            }

            /**
             *  save all polygons in a .scn file
             */
            case SAVE_POLYGONS :         
            {
                if (greenLightForFilling == true)
                {
                    saveWorkspace();
                } 
                break;  
            }   // end SAVE_POLYGONS



            case SAVE_POLYGONS_LOWERCASE:
            {
                if (greenLightForFilling == true)
                {
                    saveWorkspace();
                } 
                break;  
            }

            /**
             *  Delete everything & load all polygons from .scn file
             */
            case LOAD_POLYGONS:      
            {
                loadWorkspace();
                break;
            }   

            case LOAD_POLYGONS_LOWERCASE:
            {
                loadWorkspace();
                break;
            }

            default: break;  
        } // end switch


    } 

【问题讨论】:

  • 你应该可以通过简单地调用Component.addAction/Key/Mouse/Listener(new ActionListener() { actionPerformed(ActionEvent e) {} });来添加一个监听器
  • @mKorbel:当我点击1st 时间f 时填充多边形的目标 - 而f 只被按下一次,目标是用户将无法绘制更多多边形。只是,当用户再次点击f2nd time)时,我想删除填充并退出 while 循环,这样用户就可以添加更多多边形。
  • 然后忘记了 KeyListener(我说的是带有 Java2D 的 JPanel,而 JPanel 中没有任何 JComponents),要使用 KeyListener 的 KeyBindings,输出将是 Swing Action.is/setEnabled,您可以添加两三束 Swing Action,用 setEnabled 管理它们
  • @mKorbel:代码已附加到已编辑的帖子中。谢谢
  • 您的代码看起来很可疑:a) 在paintComponent/draw 中设置标志(可能会或不会违反never-change-state-while-painting 规则)b) while(true) doSomething 在keyListener 中(即在 EDT 上)...我认为您的状态模型需要进行一些清理,然后按照 @mKorbel 的建议使用基于该状态模型的键绑定/操作

标签: java swing listener actionlistener keylistener


【解决方案1】:

我不明白为什么不。有几件事需要考虑。

键监听器本身运行在事件调度线程上;您不希望该线程上出现此循环,因为第二个按键的代码也在该线程中运行。所以第一次按键需要启动一个 SwingWorker 或其他线程来运行填充。

我建议多边形填充器要么运行缓慢(做一点填充,然后以某种方式暂停,除非填充需要相当长的时间),否则它必然会在第二次按键之前完成填充。它可能还需要“刷新”填充输出,以便缓冲不会消除可见效果。

--- 附录

我不会创建额外的 keylistener,我只会使用我拥有的那个。我会在那个监听器中有一个布尔开关,指示我是否处于“绘图模式”;如果不是,则启动绘图循环并更改开关,如果是,则终止绘图循环并更改开关。

我会编写一个类来执行填充循环,并使其可运行。当需要启动循环时,我会实例化它并在 SwingWorker 线程中运行它。循环会填充一点,睡眠一点,然后再填充一点直到完成。我对你的填充循环一无所知,所以你必须在这里填写。

您的 keylistener 可以保留对循环填充对象的引用,并在其上调用一个方法来设置您提到的“结束循环”布尔值。该类中的循环将检查填充之间的布尔值。

网上有很多关于如何启动在事件调度线程之外运行的 SwingWorker 线程的示例;我可以创建一个,但您似乎对此没有任何具体问题,因此应该提供一般案例文档和示例。如果您尝试并遇到特定问题,请将该问题发回给 SO。

【讨论】:

  • 你能解释一下怎么做吗?
  • 基本上你的 KeyListener 代码应该只是改变状态,比如:someBollean = !someBoolean,而不是给它一个特定的值。请注意,布尔值以 false 开头。
  • @MikkelLøkke:请看结果:stackoverflow.com/questions/15764479/…
  • 不要使用 KeyListener。 Swing 旨在与键绑定一起使用。
【解决方案2】:

您可以通过以下示例:

    Component.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent e)
        {
            //Execute when button is pressed
        }
    }); 

只需将 ActionListener 更改为您需要的任何 Listener。但是,由于您已经有一个监听器,您可以只使用那个监听器。

【讨论】:

  • 你确定Component 有方法addActionListener() 吗?
  • 好吧,不要使用Component,我只是写了Component 来演示如何添加动作监听器。如果您的对象允许使用事件侦听器,则只需像这样附加所需的侦听器。
  • 此外,如果您已经将该代码包装在 Key 侦听器中,为什么不简单地重用侦听器来检查是否触发了新事件(击键)?
  • 自从我进入while循环后,程序就卡住了,直到someBoolean变成false
  • 你有两个选项在这里你可以使用一个简单的if 语句在你的同时看起来将保持外观直到按下正确的键或者你可以在while循环中添加另一个键监听器像我在您的情况下向您展示了Component 将是JFrameJPanel 或您用来绘制的任何组件。简单地重用调用您发布的代码的 Key 侦听器会产生更好的代码。但无论哪种方式都可以。
猜你喜欢
  • 2023-03-19
  • 1970-01-01
  • 2013-04-15
  • 1970-01-01
  • 2020-10-19
  • 2021-05-27
  • 1970-01-01
  • 2013-08-22
  • 2011-02-24
相关资源
最近更新 更多