Friday, November 5, 2010

MouseListener, MouseMotionListener & KeyListener

For a Sudoku game I am currently working on, I decided that I want the user to click on a cell that I have drawn on a JPanel and enter a digit using the keyboard. This is an Event Driven Programming challenge. To solve the problem I decided to use a MouseListener in order to capture the click event, a MouseMotionListener to locate the mouse pointer and a KeyListener for the digit input by pressing a key on the keyboard.

Lets start with the MouseMotionListener class. It is an inner class for the public class ClassSDK extends JPanel {} class.
private class MouseTracker implements MouseMotionListener {

        public void mouseDragged(MouseEvent e) {/*do nothing*/

        }

        public void mouseMoved(MouseEvent e) {

            //check if mouse is over the sudoku table
            if (e.getX() > inset && e.getX() < (inset + (9 * squareWidth))
                    //mouse in horizontal range; check vertical
                    && e.getY() > inset && e.getY() < (inset + (9 * squareWidth))) {
                //in sudoku table...
                //convert mouse coordinates to cell coordinates
                mouseCol = (e.getX() - inset) / squareWidth;
                mouseRow = (e.getY() - inset) / squareWidth;

                highlightCell(mouseRow, mouseCol, gBack, Color.ORANGE);

            } else {
                //set mouseCol and mouseRow to -1 identifying mouse is out of table
                mouseRow = -1;
                mouseCol = -1;
                //clear the backImg highlight effect
                highlightCell(0, 0, gBack, null);
            }
        }
    }
So in this class I am tracking the mouse over the JPanel in which I have drawn the sudoku table. Once the mouse pointer is above the sudoku table (insets is a variable that contains the size of my empty border around the table) I start converting the coordinates of the pointer to coordinates of a cell in the sudoku table. In case you don't know, a sudoku table consists of 9 rows and 9 columns. highlightCell() is a method which can either paint a specified cell in certain colour, or clear it from the colour. I will not describe how it works now though. It will be a part of my BufferedImages use blog. You will see where I initialize and add this listener to the ClassSDK JPanel in my MouseListener class:

private class ClickListen implements MouseListener {

        public void mouseClicked(MouseEvent e) {/*do nothing*/

        }

        public void mousePressed(MouseEvent e) {/*do nothing*/

        }

        public void mouseReleased(MouseEvent e) {

            //check if click was inside the sudoku
            if (mouseRow == -1 || mouseCol == -1) {
                return; //click outside sudoku table
            }
            /*check if there is an entry process already initiated (flag -1 on lockRow and lockCol means no entry process)*/
            if (lockRow != -1 || lockCol != -1) {
                //if so unload the input listener for that process
                KeyListener[] l = getKeyListeners();
                if (l.length > 0) { //if there was a key listener which should be the case
                    removeKeyListener(l[0]); //remove it
                    System.out.println("Removed previous input listener.");
                }

            }
            //ready to start input method
            createSDK();
        }

        public void mouseEntered(MouseEvent e) {

            //start tracking the mouse once entered in the component
            addMouseMotionListener(new MouseTracker());
            requestFocus(); //automatically focust the panel with the mouse over it
        }

        public void mouseExited(MouseEvent e) {

            //remove motion listener if mouse is out of panel to save ressources
            MouseMotionListener[] l = getMouseMotionListeners();
            removeMouseMotionListener(l[0]);
        }
    }
The createSDK() method is a method which controls the input together with my KeyListener class. The part where I check the variables lockRow and lockCol for a flag of -1 is that, if the user clicks on a cell and starts the entry process but does not enter a value and clicks on another cell instead, the keylistener that listens for entry in the previous cell has to be removed, else with one click of a button the value would be entered in both cells. lockRow and lockCol save the coordinates of the cell where the click occurred until the point when a value is entered and the entry process finishes, when they switch value back to -1.
    /**
     * Called by createSDK, this class waits for a digit to be entered and then
     * saves it to the mainG array, paints it on the grid.
     */
    private class InputListen implements KeyListener {

        public void keyTyped(KeyEvent e) {

            System.out.println("key typed");
            if (lockRow == -1 || lockCol == -1) //there is no lock on any cell
            {
                return;
            }

            char input = e.getKeyChar();
            //check if input is a digit
            if (Character.isDigit(input)) {
                //save input to sudoku array and
                //show input on the sudoku table
                addDigitToMainG(lockRow, lockCol, Integer.parseInt(Character.toString(input)));

                //clear visual highlight of cell and reset lock variables
                lockCol = -1;
                lockRow = -1;
                highlightCell(0, 0, gLock, null);
                //remove the key listener
                KeyListener[] l = getKeyListeners();
                removeKeyListener(l[0]);
            }
        }

        public void keyPressed(KeyEvent e) {/*do nothing*/

        }

        public void keyReleased(KeyEvent e) {/*do nothing*/

        }
    }  
 This is how the key listener works. It unloads itself once the process has finished. addDigitToMainG(int,int,int) is a method that adds a number to specific row and column in my array and then prints it on the screen as well. 

It's a lot of code and explanation and I try to be detailed in my comments, so if you have any questions please comment. This is a good exercise on event driven programming combining 3 different types of listeners.

No comments:

Post a Comment