How to use JButton with a class extending Canvas?

1k views Asked by At

I am using a class that extends Canvas in attempt to make a Conway's Game of Life copy. I am not not new to Java but I am new to both Swing and canvas. I have tried many ways of adding JButton objects to my canvas but have had no success. I have included my code, and if anyone has any advice as to how I could implement buttons it would be greatly appreciated.

import java.awt.Dimension;
import java.awt.Graphics;

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

public class ConwaysGameOfLife extends Canvas implements Runnable{
    private static final long serialVersionUID = 1L;

    public static final int SIZE = 960;

    public static final String TITLE = "Conway's Game of Life";

    private boolean running = false;
    private Thread thread;

    private static JButton but;

    public static void main(String[] args)
    {
        ConwaysGameOfLife game = new ConwaysGameOfLife();

        game.setPreferredSize(new Dimension(SIZE-10, SIZE-10));
        game.setMaximumSize(new Dimension(SIZE-10, SIZE-10));
        game.setMinimumSize(new Dimension(SIZE-10, SIZE-10));

        JFrame frame = new JFrame(TITLE);

        frame.add(game);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        but = new JButton("Button");
        frame.add(but);

        game.start();
    }

    private void start()
    {
        if(running)
            return;

        running = true;
        thread = new Thread(this);
        thread.start();
    }

    private void stop()
    {
        if(!running)
            return;

        try{thread.join();} 
        catch(InterruptedException e){}
        System.exit(1);
    }

    public void run() 
    {
        while(running)
        {
            System.out.println("RUNNING");
        }
        stop();
    }

    public void paint(Graphics g)
    {
        g.setColor(Color.BLACK);
        g.fillRect(0,0,SIZE,64);

        for(int i = 16; i < SIZE; i += 16)
        {
            g.drawLine(i,0,i,SIZE);
            g.drawLine(0,i,SIZE,i);
        }
    }
}
1

There are 1 answers

5
MadProgrammer On BEST ANSWER

The immediate problem you're having is the fact that you've added to components to the same position within a BorderLayout...

frame.add(game); // Look and me, I'm in the CENTER
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);

but = new JButton("Button");
frame.add(but);  // Look and me, I'm in the CENTER

Now, because you've not invalidated the frame after adding the button, it's not been updated yet, so it's not been displayed, but even if you did, you might find you have some weird problems as AWT components don't have a concept of z-depth, meaning that might or might not cover the button...fun stuff.

Instead, add the button to a different position within the frame/BorderLayout

frame.add(game); // Look and me, I'm in the CENTER
but = new JButton("Button");
frame.add(but, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);

Take a look at How to Use BorderLayout for more details.

I'd also be careful with breaking the paint chain of Canvas without knowing more about how painting is done. You should be calling super.paint.

In fact, in this case, there is little benifit to using Canvas (and lot of problems), instead, you should probably use JPanel and override it's paintComponent method, making sure you call super.paintComponent before you do any custom painting

See Painting in AWT and Swing and Performing Custom Painting for some more details