2

I have listener that enters this code :

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

            }
            break;

        }  // end FILL_POLYGON

When I hit f .

Is it possible to add another listener inside that while loop , so when the user hits f again , someBoolean would get false ?

Please notice , I already have a key-listener for entering the switch-case .

Regards

EDIT - Relevant code :

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


    } 
JAN
  • 21,236
  • 66
  • 181
  • 318
  • You should be able to add a listener by simply calling `Component.addAction/Key/Mouse/Listener(new ActionListener() { actionPerformed(ActionEvent e) {} });` – Sterling Duchess Apr 02 '13 at 10:58
  • @mKorbel: The goal of filling polygons when I hit for the `1st` time `f` - and while `f` was pressed only once , the goal is that the user WON'T be able to draw more polygons . Only , when the user hits `f` again (`2nd time`), I want to remove the filling and EXIT the while loop , so the user would be able to add more polygons . – JAN Apr 02 '13 at 11:23
  • then forgot for KeyListener (I'm talking about JPanel with Java2D and without any JComponents in JPanle), to Use KeyBindings insted of KeyListener, output will be Swing Action.is/setEnabled, you can to add two-three-bunch of Swing Action, manage them with setEnabled – mKorbel Apr 02 '13 at 11:27
  • @mKorbel: Code is attached to the edited post . Thanks – JAN Apr 02 '13 at 11:30
  • your code looks fishy: a) setting flags in paintComponent/draw (may or not violate the never-change-state-while-painting rule) b) while(true) doSomething in the keyListener (that is on the EDT) ... I think your state-model needs a bit of cleanup, then use keybindings/actions based on that state-model as @mKorbel suggested – kleopatra Apr 02 '13 at 11:47

2 Answers2

3

I don't see why not. There are a couple of things to consider.

The key listener itself runs on the event dispatch thread; you don't want this loop on that thread, because the code for the second keypress also runs in that thread. So the first keypress needs to start a SwingWorker or some other thread to run the fill.

I would suggest that the polygon filler either operate slowly (do a little filling and then pause somehow unless filling takes a noticeable amount of time), otherwise it is bound to complete filling before the second keypress. It may also need to 'flush' the filling output so that buffering doesn't remove the visible effect.

--- addendeum

I wouldn't create an additional keylistener, I would just use the one I had. I would have a boolean switch in that listener that indicated whether I was in "drawing mode" or not; if not, start the drawing loop and change the switch, if so, terminate the drawing loop and change the switch.

I would write a class which job it was to execute the filling loop, and make it runnable. When it was time to start the loop, I would instantiate it and run it in a SwingWorker thread. The loop would fill a little, sleep a little, and then fill a little more until done. I don't know anything about your fill loop, so you'll have to fill in here.

Your keylistener could keep a reference to the loop-filling object, and call a method on it to set the "end loop" boolean you mention. The loop in that class would check the boolean between fills.

There are many examples available on the web of how to start a SwingWorker thread that operates outside the event dispatch thread; I could create one, but you don't seem to have any specific question about it, so the general-case documentation and examples should serve. If you try it and run into a specific problem, post that question back to SO.

arcy
  • 12,845
  • 12
  • 58
  • 103
  • Can you please explain how to do that ? – JAN Apr 02 '13 at 11:03
  • Essentially your KeyListener code should just change the state, so something like: someBollean = !someBoolean, rather than giving it a specific value. Note that booleans start out as false. – Mikkel Løkke Apr 02 '13 at 11:54
  • @MikkelLøkke: Please see the results : http://stackoverflow.com/questions/15764479/java-listener-inside-a-loop-wont-allow-to-change-an-outsider-boolean-flag . – JAN Apr 02 '13 at 12:48
  • Don't use a KeyListener. Swing was designed to be used with Key Bindings. – camickr Apr 02 '13 at 15:33
0

You can by following example:

    Component.addActionListener(new ActionListener() {

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

Simply change ActionListener to whatever Listener you need. However since you already have a listener that for Key strokes you could possibly just use that one..

Sterling Duchess
  • 1,970
  • 16
  • 51
  • 91
  • Are you sure that `Component` has a method `addActionListener()` ? – JAN Apr 02 '13 at 11:07
  • Well dont use `Component` i simply wrote `Component` to demonstrate how to add action listener. If your Object allows the use of Event Listeners then simple append the desired listener like so. – Sterling Duchess Apr 02 '13 at 11:09
  • In addition if you already have that code wrapped in a Key listener why not simply reuse the listener to check if a new event(key stroke) has been fired ? – Sterling Duchess Apr 02 '13 at 11:11
  • Since when I enter the `while` loop , the program is stuck until the `someBoolean` would be `false` . – JAN Apr 02 '13 at 11:18
  • You have two options here mate you can use a simple `if` statement in you while look that will hold the look until proper key is pressed or you can add another Key listener in the while loop like i showed you in your case `Component` would be `JFrame` or `JPanel` or whatever component you are using to draw. Simply reusing your Key listener that invokes that code you posted would result in better code. But either way will work. – Sterling Duchess Apr 02 '13 at 11:21
  • Also if you could post your code including the `KeyListener` we could help you better. – Sterling Duchess Apr 02 '13 at 11:23
  • The code is attached to the edited post . Please notice that once you enter the while loop , you're there forever , until the boolean changes , no ? – JAN Apr 02 '13 at 11:29