Jon Snow
Jon Snow

Reputation: 240

Using Graphics with Key Listener

So for an assignment, I'm supposed to make hangman using graphics and keylistener. The user inputs letters directly from the keyboard. I am having this issue where after I do anything with key listener, graphics stop working.

When I call the checkHangman() method (which will eventually call the fillLetters() method) in the paint() method, the letter is drawn. However, if I call the checkHangman() method from the keyPressed() method of keylistener, graphics stop working.

I placed print statements in the fillLetters() method after the draw command so I know that the method and command are both called, but nothing shows on the screen when checkHangman() is called from keyPressed(). I've tried using repaint() and have checked to make sure that the graphics object the keyPressed() method passes as a parameter is the same one that the other methods use. At this point I've worked on this for hours but am still stuck. Any help is appreciated.

import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;

public class Hangman {
    public static void main(String args[]) {
        GfxApp gfx = new GfxApp();
        gfx.setSize(1000,750);
        gfx.addWindowListener(new WindowAdapter() {public void
        windowClosing(WindowEvent e) {System.exit(0);}});
        gfx.show();
    }
}
class GfxApp extends Frame implements KeyListener {
    boolean added = false;
    private int tries = 0;
    String word;
    ArrayList<blanks> blank = new ArrayList<blanks>();
    HashSet<Character> used = new HashSet<Character>();
    HashSet<Character> notused = new HashSet<Character>();
    Graphics g;

    class blanks {
        private int x;
        private int y;
        private int x2;
        private int y2;
        private Graphics g;
        public blanks(int x, int y, int x2, int y2,  Graphics g) {
            this.x = x;
            this.y = y;
            this.x2 = x2;
            this.y2 = y2;
            this.g = g;
            drawBlank();
        }
        private void drawBlank() {
            g.setColor(Color.white);
            g.drawLine(x,y,x2,y2);
        }
        public void fillLetters(Graphics g, char lett) {
            g.setFont(new Font("COURIER NEW", Font.BOLD, x2-x));
            g.drawString(String.valueOf(lett), x, y);
            System.out.println("WE GOT HERE");   //this prints everytime I type something
        }
    }
    public void getWord() throws IOException
    {
        Scanner scanner = new Scanner(new File("Hangman.txt"));
        word = scanner.next();
    }

    public void paint(Graphics g){
        if(added == false)
        {
            addKeyListener(this);
            added = true;
        }
        g.setColor(Color.black);
        g.fillRect(0,0,1000,750);
        try{
            getWord();
        } catch (IOException e){
            System.out.println("Completed!");
        }
        drawHangman(g);
        drawBlanks(g, word);
    }
    private void drawHangman(Graphics g){
        g.setColor(Color.white);
        g.drawLine(50, 700, 200, 700);
        g.drawLine(125,75 , 125, 700);
        g.drawLine(125, 75, 300, 75);
        g.drawLine(300, 75, 300,150); 
        this.g = g;
    }
    public void checkHangman(Graphics g, char letter, String word) {
        char lett = Character.toLowerCase(letter);
        boolean check = false;
        g.setColor(Color.white);
        for(int i = 0; i < word.length(); i++) {
            char filler =  Character.toLowerCase(word.charAt(i));
            if(filler == lett) {
                check = true;
                break;
            } else {
                continue;
            }
        }
        if(check) {
            fillInLetters(g, letter, word);
        } else {
            tries++;
            switch(tries) {
                case 1: g.drawOval(250,150, 100,100); break;
                case 2: g.drawLine(300, 250, 300, 450); break; 
                case 3: g.drawLine(225, 625,300, 450); break; 
                case 4: g.drawLine(375, 625,300, 450); break;
                case 5: g.drawLine(300, 300, 200, 388); break;
                case 6: g.drawLine(300, 300, 400, 388); break;
                case 7: g.drawOval(270, 170, 20, 20); break;
                case 8: g.drawOval(310, 170, 20, 20); break;
                case 9: g.drawArc(275, 215, 50, 40, 0, 180); break;
            }
        }
    }
    public void fillInLetters(Graphics g, char letter, String word) {
        char check = Character.toLowerCase(letter);
        for(int i = 0; i < word.length(); i++) {
            char lett = Character.toLowerCase(word.charAt(i));
            if(check == lett) {
                blank.get(i).fillLetters(g, lett);
            }
        }
    }
    public void drawBlanks(Graphics g, String word) {
        int num = word.length();
        double sections = (double)(950-350)/num;
        int line = 350;
        for(int i = 1; i <= num; i++) {
            blank.add(new blanks(line, 150, line + (int)(sections) - 10, 150, g));
            line  += sections;
        }
    }

    public void keyPressed(KeyEvent e){
        char letter = (char) e.getKeyCode();
        used.add(new Character(letter));

        if(!notused.contains(new Character(letter)))
        {
            notused.add(new Character(letter));
            System.out.println(letter);
            checkHangman(g, letter, word);
        }
    }

    public void keyReleased(KeyEvent e){
        System.out.println("Key Released!!!");

    }

    public void keyTyped(KeyEvent e){
        System.out.println("Key Typed!!!");
    }
}

Sample output for the word "APPLE".

Upvotes: 0

Views: 1071

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

Start by taking a look at Performing Custom Painting and Painting in AWT and Swing

Painting is controlled by the Swing paint subsystem in a defined manner.

You should start by overriding the component's paintComponent method, and when it's called, paint the current state of the component.

You should use repaint to request that system schedule a paint event to update your UI

I'd also discourage you from overriding paint of top level containers like Frame apart from not been double buffered, you're also running the risk of painting under the frame decorations

As a general rule of thumb, don't maintain a reference to a Graphics context you didn't create yourself

Upvotes: 1

Related Questions