Figuring out the Mouse Listener

I’m taking a java class and have to make a Black Jack game for the final and I wanted to implement a GUI for it. Only problem is I don’t really know how to use the Mouse Listener. Or rather, I don’t know how to get it to do what I want it to do. For now all I want to do is draw a string when I button is clicked or pressed. I can get it to print in the command line but it won’t draw the string. I’m also going off of the experience I got from making a pong game for my midterm so I don’t know if some of this stuff is needed for a game like Black Jack. Here’s what I got to start off with if it helps you at all, any help is appreciated.

public class BlackJack extends JPanel implements Runnable, KeyListener, MouseListener {

    private JButton button = new JButton("This is a JButton");
    boolean buttonClicked;


    public BlackJack() {
            JFrame frame = new JFrame("BlackJack");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new FlowLayout());
            frame.setSize(500,500);
            button.addMouseListener(this);
            frame.add(button);
            frame.setVisible(true);
            button.setVisible(true);


    }



    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        if(buttonClicked)
        {
            g.setColor(Color.BLACK);
            g.drawString("The button was clicked", 50,50);
        }
    }

    public void mouseClicked(MouseEvent e) {
        
        if(e.getSource().equals(button))
        {
            if(!buttonClicked)
                buttonClicked = true;
            else
                buttonClicked = false;

        }
        
    }

    public void start(){
        Thread th = new Thread (this);
        th.start ();
    }

    public void run(){

        while(true)
        {
            try
            {
                Thread.sleep (25);
            }
            catch (InterruptedException ex){}
        }
        
    }

I think that’s all I need to put up for this. Anything else I have so far is just empty key and mouse listener methods.

That should solve your immediate problem, but if someone clicks and releases in less than 25ms (unlikely) then it won’t work!

And you can replace these lines:


if(!buttonClicked)
    buttonClicked = true;
else
    buttonClicked = false;

with this 1 line:


buttonClicked = !buttonClicked;

;D

Ah. I completely forgot about the repaint(), sadly that didn’t fix it. After having the time to mess with it a bit I found that the paintcomponent isn’t doing anything at all, and with the setLayout thing it sets the button in the center of the frame and can’t really change it’s location, and without the layout, the button takes up the whole panel. I thought about making the frame and everything in the main class like I did with my pong game and scrap the constructor but then I wouldn’t be able to use the button in the Black Jack class. I’m kinda at a loss of what to do lol.

Does anything call the start() method? If nothing calls it, then your thread isn’t initialized, therefore you have no loop.

Assuming your BlackJack game is single player (i.e. not-networked) and uses minimal animation, I would suggest not using any threading at all and take out all references to Runnable, Thread, run(), etc.

This will:
a) simplify your program and remove a lot of potential problems that threading can cause with painting
b) allow you to focus on painting and get a better understanding on how Java passive rendering works

I had it in the main but I guess I forgot to include the main in my post.
I decided to start over with this class and see if that would make a difference but paintComponent still isn’t doing anything. All I have for it is this.

public class BlackJack extends JPanel implements KeyListener, MouseListener {

    private JButton button = new JButton("This is a JButton");
    boolean buttonClicked;

    public BlackJack()
    {
        JFrame frame = new JFrame("BlackJack");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setVisible(true);
        frame.setSize(500,500);
        frame.addKeyListener(this);
        frame.addMouseListener(this);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        g.setColor(Color.BLACK);
        g.fillRect(1, 1, getWidth(), getHeight());
    }

    public void run()
    {
        while(true)
        {
            repaint();
            try{
                Thread.sleep(1000);
            }
            catch(InterruptedException e){}

        }
    }
}

public static void main(String[] args) {
    BlackJack game = new BlackJack();
    game.run();
}

At this point I’m just trying to get it to draw anything…I could just be being very stupid about this as I am tired from work and it’s almost 1am. Maybe I’ll figure it out in the morning or something.

I think the JFrame should be the outermost container. I’d instantiate the JFrame in my BlackJack class, then “add” a BlackJackJPanel (separate class, subclassing JPanel) to the JFrame, and put my button in the subclassed JPanel. You could also probably just put the button in the “content pane” of the JFrame and skip the JPanel.

When a Button is clicked, it’s “listener” will call a method called “actionPerformed()” which is where you could set the state variable that the paintComponent() method refers to when it executes. But be sure and actually call a repaint() if you want paintComponent() to run.

Here’s the tutorial on ActionListenter:
http://download.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
If you get stuck just trying to get basic stuff to display, there’s this demo:
http://download.oracle.com/javase/tutorial/uiswing/examples/components/FrameDemoProject/src/components/FrameDemo.javaThey add a blank label, which is kind of silly. You could use a similar command to load your JButton.

Swing’s events are not thread safe, this means your thread calling ‘repaint’ can potentially be run simultaneously as the code in your mouse and keyboard listeners. Further Swing can call repaint at any time, such as when a window is resized. So you will have times where repaint is simultaneously called twice (once by your thread and once by Swing)!

So I’d advise looking into using action listeners for storing all of your code, and don’t use threads at all. You can move the ‘repaint’ call into your action listeners so it’s always repainted when clicked. This would also be more efficient since your not constantly repainting.

You can build it your way (using threads), but to do it properly involves thread locking to ensure you can’t have repaint called simultaneously twice (and other threading bugs).

Just pointing out that although repaint() is called from the ‘wrong thread’, the actual painting will occur on the EventDispatchThread, so there won’t be ‘other threading bugs’ as a result of his code, just the problem of painting too often. sometimes.

Alright, so I’ve pretty much figured out what I need to know for the action listener, I think. I’m still having troubles with what I want to do with the gui part. I tried making the frame and everything in the BlackJack constructor but then the paint component wouldn’t do anything. If I made the frame and everything in main the paint component works but I’m not quite sure how to get the action listener to work if I have to add stuff to the gui from main. I’m pretty much learning this on my own as this isn’t really covered in the class at all.
Should I be going with this?

The subclassing JPanel would be the “extends JPanel” part, right? We’re just getting into super/sub classes and whatnot so I’m not sure if I completely understand it yet. So, if I did this, I’d need to instantiate the blackjackpanel and add it to the frame in blackjack and I’d be able to use the button and actionlistener and all that? Would I need to put the paintcomponent in the blackjackpanel too? Or could I leave it in the blackjack class?

Yes, “class BlackJackPanel extends JPanel” should work.

This is what I’ve done, but I am also a relative beginner, so hopefully some other folks will weigh in as well:

I have no paintComponent() method in the JFrame, but do have a paintComponent() in the JPanel (your BlackJackPanel in this case). Within my JPanel constructor, I do an “addMouseListener” & “addMouseMotionListener” and also I create a MenuBar and add ActionListeners to the menubar’s JMenuItem objects. The ActionListeners are themselves created as inner classes. (But you could do it as an “anonymous” inner class. More terms to learn about. Oh joy!)

Something similar should work for a JButton instantiated and added to the BlackJackPanel. You can add an actionListener to your JButton.

Also, I do a “setSize” in the JFrame.

My ‘in progress’ puzzle game is Hexara, if you are curious. ‘no sound’ version of puzzle: http://www.hexara.com/gameNS.html (Discussion thread when I first presented the code is here:http://www.java-gaming.org/index.php/topic,23676.0.html.)

For simply flipping cards, or displaying a message from a button, JPanels are fine. For more intense animation, a lot of folks get into using the Canvas, and there are some good tutorials from Oracle on that. But first things first.

@philfrei
Just pointing out that JFrame doesn’t even have a paintComponent(). That’s only for JComponent and its subclasses :wink:

Doh! Thanks.

Working a bit more with the action listener. In the blackJackPanel I have small menu bar set up and one of the options is to start a new black jack game. So clicking that would call the method in blackJack that starts running the game but I can’t really do that cause I’d need to instantiate blackJack and doing that in blackJackPanel causes a stack overflow or something. I can easily just get it done by having the actionPerformed in blackJack do this but I was wondering if there was a way to do it from the panel class. Thanks for all your help guys, I really really appreciate it. Also, philfrei, your Hexara game looks pretty good. How long has it taken you to make that?

A stack overflow exception usually occurs due to infinite loops. Look over your code in your constructor and try pinpointing where an infinite loop might be started.

I’m not too sure what would be causing an infinite loop in the constructor, maybe you can see it?
Here’s what I got.

public class BlackJackPanel extends JPanel implements ActionListener {

    BlackJack blackJack = new BlackJack();
    JButton button = new JButton("Button");
    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("Stuff");
    JMenuItem menuStart = new JMenuItem("Start");
    JMenuItem menuExit = new JMenuItem("Exit");
    boolean buttonClicked;

    public BlackJackPanel(){
        button.addActionListener(this);
        menuStart.addActionListener(this);
        menuExit.addActionListener(this);
    }


    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.blue);
        g.fillRect(1, 1, this.getWidth(), this.getHeight());
        g.setColor(Color.yellow);
        if(buttonClicked)
        {
            g.drawString("CATS a;kldsjf;lkadjfl;kadkj;fas", 50, 50);
        }

    }

    public void actionPerformed(ActionEvent e) {

        if(e.getSource().equals(button))
        {
            buttonClicked = !buttonClicked;
            repaint();
        }
        if(e.getSource().equals(menuStart))
        {

        }
        if(e.getSource().equals(menuExit))
            System.exit(0);
    }

}

public class BlackJack extends JPanel implements ActionListener, KeyListener, MouseListener {

    BlackJackPanel panel = new BlackJackPanel();
    private int credits;
    boolean validInput;
    Random myR = new Random();




    public BlackJack()
    {
        JFrame frame = new JFrame("BlackJack");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setSize(500,500);
        frame.add(panel);
        panel.add(panel.button);
        panel.menuBar.add(panel.menu);
        panel.menu.add(panel.menuStart);
        panel.menu.add(panel.menuExit);
        panel.menuStart.addActionListener(this);
        panel.menuExit.addActionListener(this);
        frame.setJMenuBar(panel.menuBar);
        frame.setVisible(true);

    }


    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource().equals(panel.menuStart))
        {
            run();
        }
    }
     
    public void run()
    {
        while(true)
        {

        }   
    }

Yikes.

You don’t have to do an “implements ActionListener”. Also I meant to make BlackJack.java the main file. Maybe the easiest thing is to hack up an example of the “template” that I use, with some of your code fragments. There are some simplifications here that are not the best Java form. But maybe this will be an ok learning structure that you can build from.

Thanks for thumbs up on Hexara. I started it a little over a year ago as a learning project. Been working on it part time, and hardly at all lately. I’m working on a little “wav scratcher” app as a way of learning more about sound at the moment.

import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BlackJack 
{
    public static void main(String[] args) 
    {
        JFrame frame = new GameFrame();
        frame.setDefaultCloseOperation(
                JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

class GameFrame extends JFrame 
{ 
    GameFrame()
    {
        setTitle("Black Jack Project");
        setSize(500, 500);         
        BlackJackPanel bjp = new BlackJackPanel();
        add(bjp);
    }
}    

class BlackJackPanel extends JPanel
{
    boolean buttonClicked;
    JButton button;
    
    BlackJackPanel()
    {
        button = new JButton("Button");
        add(button);
        button.addActionListener(new ButtonListener());
    }
    
    public class ButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent arg0)
        {
            buttonClicked = !buttonClicked;
            repaint();
        }
    }
    
    public void paintComponent(Graphics g)
    {
        g.clearRect(0, 0, 500, 500);
        if (buttonClicked)
        {
            g.drawString("CATS a;kldsjf;lkadjfl;kadkj;fas", 50, 50);
        }
    }
}

Ah, thank you so much! I was wondering how I set where the button shows up. I messed around with it a bit earlier but I was never able to change the location of the button when everything is first initialized. It always stays center aligned at the top. It seems that I can set the location of it any time after it’s started but if I do something like resize the window goes back to being at the top and centered.
I was also thinking of adding a little casino music or something but I’m not too worried about that.

In your code, you never add the JMenuItem’s to your JMenu :wink:
Ah didn’t see your BlackJack class :smiley:

Anyway, I don’t see anything wrong in your code. Could you give us the stack trace of that StackOverflowException?