-3

I'm having a couple of different problems with my code, most of them are GUI based problems but i do have one actionevent problem. I will post my code in sections first then I will point out what the issue is specifically with each section. *note all of my code will be in order of how is actually in my IDE.

If you wish to copy my code without all of the other stuff here it is on pastebin: http://pastebin.com/HHjRRtGZ

My imports:

import java.awt.*;
import java.awt.event.*;

import javax.swing.*; //Makes it a Japplet

import java.util.Random;

My Program Starts here:

public class Hangman extends JApplet implements ActionListener {

    // How many times you can guess the wrong letter till you lose
    static final int DEAD = 7;   

    private int errors;        // amount of errors
    private String message;   // Message displaying either Error or Victory
    private String information; // Secondary Message
    private String RealWord;      // The Real word
    private StringBuffer GuessWord;// The Guessed word
    private Button StartBtn;      // The Restart Button
    private Button GoBtn;         // The Go Button
    private TextField LetterBox; // The LetterBox

My ActionEvent:

    public void actionPerformed(ActionEvent e){

        if (e.getSource() == StartBtn){
            initGame();
        }

        if (e.getSource() == GoBtn){

            processTurn();

            LetterBox.setText("");
            repaint();
        }
    }

Problem One:

The problem that I am having with my Action event is that when I hit the StartBtn it does not reinitialize everything. Nothing is cleared. Nothing is done. It doesn't do anything. So that's the issue there.

My init() function (This is where one of my problems lie.

    public void init() {

        // Create a "Textbox" for the letter guessing
        LetterBox = new TextField();

        //Create my buttons and labels
        StartBtn = new Button("Restart");
        GoBtn = new Button("Go");

        //Add the elements to the applet

        JPanel p = new JPanel();
        p.setLayout(new FlowLayout());

        p.add(StartBtn);
        p.add(new Label("Guess a letter"));
        p.add(LetterBox);
        p.add(GoBtn);

        add(p, BorderLayout.SOUTH);

        //Make buttons event listeners
        StartBtn.addActionListener(this);
        GoBtn.addActionListener(this);

        //Startup the Game
        initGame();

    }

Problem 2 (MAIN PROBLEM):

The problems I have with my Init code that affect my GUI is that the actual word guess area and the hangman area are kind of messed up. It's hard to explain, so i'll show you an image. The Backdrop for almost all of the form is completely transparent. So it just uses a still image of whatever it was on top of as it's back ground.

Problem 3: There are some other issues with the image as you can see. The code is further down for those parts however. But as you can tell, the messages do not clear and just write over each other, even though I specify them to (which you will see further down).

Problem 4: Now before you guess any letters, the word is hidden with a "" but when you guess a correct letter for the word it's supposed to replace the "" with the correct letter guessed. However it just put's it on top of it (you will see the code for this below as well).

Messed up Graphics

This is the Game initializer

    public void initGame() {
        //Set the errors to 0
        errors = 0;

        //Enter the wordslist, separated by a | here
        String str = "write|program|receive|positive|variables|temporary|good|bad|test";        
        String[] temp;


        //delimiter
        String delimiter = "\\|";

        // given string will be split by the argument delimiter provided.
        temp = str.split(delimiter);

        //Create the Random Seed Generator
        Random RandGenerator = new Random();

        //Generate my Random Number
        int randomInt = RandGenerator.nextInt(temp.length);

        RealWord = new String(temp[randomInt]);

        char positions[] = new char[RealWord.length()];

Right here is where it replaces the unguessed characters on screen with a "*".

        for (int i = 0; i < RealWord.length(); i++) {
            positions[i] = '*';
        }


        String s = new String(positions);
        GuessWord = new StringBuffer(s);

        LetterBox.setText("");

        //Delete Messages
        message = "";
        information = "";
        repaint();
    }

My Painting function

    @Override
    public void paint(Graphics g) {

        int BaseY = 250;

        //THE HANGING STAND
        if (errors > 0) { //1 Error
            g.drawLine(90, BaseY, 200, BaseY); //The ground
            g.drawLine(125, BaseY, 125, BaseY-100); //The bar going up
            g.drawLine(125, BaseY-100, 175, BaseY-100); //The sidebar
            g.drawLine(175, BaseY-100, 175, BaseY-75); //The Rope
        }

        //THE PERSON
        if (errors > 1) { 
           g.drawOval(170, BaseY-75, 10, 12); // The Head       
        }

        if (errors > 2) { 
           g.drawLine(175, BaseY-62, 175, BaseY-45); // The Body    
        }

        if (errors > 3) { 
           g.drawLine(165, BaseY-65, 175, BaseY-55); // Left Arm  
        }

        if (errors > 4) { 
           g.drawLine(185, BaseY-65, 175, BaseY-55); // Right Arm 
        }

        if (errors > 5) { 
           g.drawLine(170, BaseY-30, 175, BaseY-45); //Left Leg       
        }

        if (errors > 6) {  //7 Errors
           g.drawLine(175, BaseY-45, 180, BaseY-30); // Right Left 
        }


        //Show Messages/Errors
        g.drawString(message, 40, BaseY+25);
        g.drawString(information, 25, BaseY+45);
        g.drawString(new String (GuessWord), 140, BaseY-120);

        g.drawString(new String("WELCOME TO HANGMAN!"), 75, 40);
    }

This is where alot of the magic happens. This is the processTurn Function

    private void processTurn() {

        String s, t;
        char a;

        s = LetterBox.getText();
        a = s.charAt(0);

        if (!Character.isLetter(a)) {
            message = "Only enter letters please.";
            return;
        }

        if (s.length() > 1) {
            message = "One letter at a time please.";
            return;
        }

        //Check if letter has been used already
        t = new String(GuessWord);
        if (t.indexOf(s) != -1) {
            message = "You have already guessed with that letter!";
            return;
        }

        //If the letter you guessed does not occur in the Real Word
        if (RealWord.indexOf(s) == -1) {

            message = "";
            errors++;

            if (errors==DEAD) {
                message = "Sorry, you lose";
                information = "Click restart to try again!";

                //INSERT MOVING HANGMAN HERE.
            }

            return;
        }

This is where the "*" is supposed to be replaced with the correctl guessed letter but it doesn't work correctly!

        //Replace stars in the Guessed Word with the found letter
        for (int i = 0; i < RealWord.length(); i++) {
            if (RealWord.charAt(i) == a) {
                GuessWord.setCharAt(i, a);
            }
        }

        t = new String(GuessWord);

        //If all of the stars have been filled, then you win!
        if (t.indexOf('*') == -1) {
            message = "You have won!";
            return;
        }

        //Delete the Message
        message = "";
        repaint();
    }

Main Function

    public static void main(String[] args) {

        JFrame frame = new JFrame();
        JApplet applet = new Hangman();

        applet.init();
        applet.start();
        frame.add(applet);

        frame.setSize(300, 400);
        frame.setLocationRelativeTo(null); // Center the frame
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);


    }
}

Any and all assistance will be greatly appreciated :) Thanks in advance!

Richard Paulicelli
  • 129
  • 3
  • 6
  • 23
  • 1) You posted way too much code 2) You asked way too many unrelated questions. Try focusing on one problem at the time 3) Do not override `paint` but override `paintComponents` instead (and call `super.paintComponents` in the overridden method – Robin Dec 09 '13 at 21:52
  • 1) I posted all of my code because all of it was relevant 2) I asked all of these questions many of them related (because all but one of them are GUI based) 3) I tried that and it gave me an error when i added super.paintCompenents. I came here to ask for help, not to be told that I need to ask for help a different way when i did it properly, formatted, and kindly. – Richard Paulicelli Dec 09 '13 at 21:55

2 Answers2

2

This is caused by the basic fact that you have broken the paint chain.

Painting in AWT/Swing is made of a chain of method calls. If you neglect to maintain this chain, you start ending up with paint artifacts, in the form you are seeing.

The Graphics context is a shared resource, that is, every component painted during any given paint cycle will be given the same Graphics resource. Each component is expected to prepare the Graphics context before painting to it...

To fix the problem, in all your paint methods, you should be calling super.paint(g) to ensure that the paint chain is maintained and that the Graphics context is preapred for the individual components painting needs.

Having said that. It is not recommended to override paint of top level containers. Instead, it is recommended that you perform your custom painting using something like a JPanel and override it's paintComponent method instead (ensuring that you call super.paintComponent as well!)

This has a least two basic benefits. The first is, you can know decide where the panel should be displayed, for example, you could add it to an JApplet or JFrame or other container as you see fit. It is double buffered by default. This means you won't see any flicker when the painting is updated.

You should consider breaking your application down into small panels, focusing on each of the components needs separately. This will help reduce the complexity of your application and make it easier to manage the individual needs of each section of your application.

Take a look at Performing Custom Painting and Painting in AWT and Swing for more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • +1 for detailing the original issue of a broken paint chain. – tenorsax Dec 09 '13 at 22:26
  • @Aqua If you update you answer to mention not calling `super.paint`, I'd be more inclined to provide an up-vote ;) - Because the rest of you answer is great advice... – MadProgrammer Dec 09 '13 at 22:27
  • @MadProgrammer Can you look at my renditioned code? I revised it alot. pastebin.com/66Q70f5X I created a public Constructor for my Hangman class and I also created another class to hold almost everything. And it provides the bottom bar (The textbox and buttons and such) but the rest of it is blank (which is good because it was transparent before hand), but it's not drawing anything now :( – Richard Paulicelli Dec 09 '13 at 22:55
  • @MadProgrammer could you please look at my new code and tell me what i'm still doing wrong? http://pastebin.com/66Q70f5X – Richard Paulicelli Dec 09 '13 at 23:16
1

The problem is that you're painting directly on JApplet. You should not paint directly on top level container such as JFrame or JApplet. Instead, use JComponent or JPanel. Override paintComponent() for painting rather than paint() and don't forget to call super.paintComponent(g).

Take a look at Performing Custom Painting tutorial for more information.

Consider refactoring your code by moving all the current logic and painting into a new JPanel which will be used as applet content. Then, add this panel to the applet.

EDIT:

The source of the problem is not calling super.paint() in you painting implementation. Overriding paint() is not necessary and usually not recommended in many Swing applications. JComponent.paint() (a superclass for all Swing components) handles painting the content, borders, and children of a Swing component. And by neglecting a call to super.paint() you are disrupting the painting of all these details.

Take a looks at A Closer Look at the Paint Mechanism for more details about painting cycle.

tenorsax
  • 21,123
  • 9
  • 60
  • 107
  • Okay, so what code and where do i need to exactly change in order to implement this? – Richard Paulicelli Dec 09 '13 at 22:18
  • 1
    That's great advice, but (from my perspective), the problem isn't the fact that they've overridden `paint` of a top level container (while certainly ill advised, it's not the cause of the problem) - but you are close ;) – MadProgrammer Dec 09 '13 at 22:22