0

I made a simple drawing program in Java using a JFrame (my first time with such). The user and click and drag to draw shapes, but that's not important. I have a JMenuBar with a bunch of options, like type of shape, New, and Quit. When the user clicks the new button, it's supposed to clear the screen. When the user hits Ctrl+N, this works just fine. However, when the button is clicked, it doesn't work at all.

I put a debugging System.out.println inside of the actionEvent for newItem and it prints out just fine when the item is clicked, but it doesn't actually erase the screen. Any idea what would cause this?

I cut out the majority of the program and left as much as was necessary to see the problem. You can still press and drag to draw a shape (the shape doesn't appear until you release the mouse button), and hit Ctrl+N to clear the screen, but clicking New doesn't do it.

import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import javax.swing.*;

public class E3G04 extends JFrame implements WindowListener, ActionListener, MouseListener, MouseMotionListener
{
    //Variables are declared as volatile to ensure that they're always called from system RAM
    static volatile String type = "rectangle";
    static volatile Boolean fill = true;
    static Color lineColor = Color.BLACK;
    static Color fillColor = Color.RED;
    static int size = 1;

    CanvasEX cx = new CanvasEX();

    static boolean running = true;

    JMenuBar mb = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
            JMenuItem newItem = new JMenuItem("New");
            JMenuItem quitItem = new JMenuItem ("Quit");


    protected E3G04()
    {

        mb.add(fileMenu);
        fileMenu.add(newItem);
        fileMenu.add(quitItem);             
        newItem.setMnemonic('N');
        quitItem.setMnemonic('Q');
        newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
        quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));          
        newItem.addActionListener(this);
        quitItem.addActionListener(this);
        cx.setSize(800,600);
        cx.addMouseListener(this);
        cx.addMouseMotionListener(this);
        setJMenuBar(mb);
        setBounds(100,100,800,600);
        setLayout(new BorderLayout());
        add("Center",cx);
        addWindowListener(this);
        setResizable(true);
        setVisible(true);
    }

    public static void main(String [] args)
    {
        new E3G04();
    }

    public void stop()
    {
        newItem.removeActionListener(this);
        quitItem.removeActionListener(this);    
        dispose();
        System.exit(0);
    }

    public void actionPerformed(ActionEvent e)
    {
        Object o = e.getSource();

        if (o == newItem)
        {
            cx.erase = true;
            cx.repaint();
        }

        if (o == quitItem)
        {   
            running = false;
            stop();
        }

    }      

    public void mousePressed(MouseEvent m)
    {
        cx.start = m.getPoint();
        cx.end = cx.start;
        cx.cur = cx.start;
    }

    public void mouseDragged(MouseEvent m)
    {
        cx.cur = m.getPoint();
    }   

    public void mouseReleased(MouseEvent m)
    {
        cx.end = cx.cur;
        cx.repaint();
    }   
    public void itemStateChanged(ItemEvent e)
    {
        Object o = e.getSource();

    }
    public void windowClosing(WindowEvent e)
    {
        running = false;
        stop();
    }
    public void mouseClicked(MouseEvent m){}    
    public void mouseExited(MouseEvent m){}
    public void mouseEntered(MouseEvent m){}    
    public void mouseMoved(MouseEvent m){}
    public void windowClosed(WindowEvent e){}
    public void windowOpened(WindowEvent e){}
    public void windowActivated(WindowEvent e){}
    public void windowDeactivated(WindowEvent e){}
    public void windowIconified(WindowEvent e){}
    public void windowDeiconified(WindowEvent e){}
}


class CanvasEX extends Canvas
{
    Point start = new Point(100,100);
    Point cur = new Point(100,100);
    Point end = new Point(100,100);
    Image offscreen;
    boolean erase = false;

    public void update(Graphics g)
    {
        //This is adds the new stuff to the screen or erases the screen if erase is true
        Graphics buffer;
        if (offscreen == null)
        {
            offscreen = createImage(getWidth(), getHeight());
        }
        buffer = offscreen.getGraphics();
        if (erase)
        {
            buffer.setColor(getBackground());
            buffer.fillRect(0,0,800, 600);
            buffer.dispose();
            erase = false;
        }
        paint(buffer);
        g.drawImage(offscreen, 0, 0, this);
    }   

    public void paint(Graphics g)
    {
        Graphics buffer = g;
        if (erase)
        {
            g.dispose();
            erase = false;
        }   
        g.setColor(E3G04.lineColor);
        if (end.x > start.x && end.y > start.y)
            g.fillRect(start.x,start.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));
        if (end.x > start.x && end.y < start.y)
            g.fillRect(start.x,end.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));  
        if (end.x < start.x && end.y > start.y)
            g.fillRect(end.x, start.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));
        if (end.x < start.x && end.y < start.y)
            g.fillRect(end.x, end.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));
        g.setColor(E3G04.fillColor);
        if (end.x > start.x && end.y > start.y)
            g.fillRect(start.x + E3G04.size,start.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);
        if (end.x > start.x && end.y < start.y)
            g.fillRect(start.x + E3G04.size,end.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);  
        if (end.x < start.x && end.y > start.y)
            g.fillRect(end.x + E3G04.size, start.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);
        if (end.x < start.x && end.y < start.y)
            g.fillRect(end.x + E3G04.size, end.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);          
    }
}
Alex Kibler
  • 4,674
  • 9
  • 44
  • 74
  • Have you heard of arrays and loops? You can shorten the code dramatically if you use them. – Nikolay Kuznetsov Dec 10 '12 at 05:50
  • Of course I have. Why do you ask? – Alex Kibler Dec 10 '12 at 05:50
  • Or is this code generated by some programm? – Nikolay Kuznetsov Dec 10 '12 at 05:51
  • Why are you are using `ItemListener` for the menu items, why not use `ActionListener` for all of them?? – MadProgrammer Dec 10 '12 at 05:53
  • Oh, right, I can do that now. I was using AWT and the regular MenuBar instead of JMenuBar before so I was using CheckboxMenuItems. I'll actually change that really quickly. Is that related to my problem, though? Because NewItem is using ActionListener – Alex Kibler Dec 10 '12 at 05:54
  • Replaced all the ItemListener stuff with ActionListener – Alex Kibler Dec 10 '12 at 05:57
  • *Here's the whole program, because I don't know where the problem is isolated.* You could of course always try to strip it down. Either the problem disappears and then you know in which part of the code it is located, or you end up with an [SSCCE](http://sscce.org) which illustrates your problem. Both approaches are preferred over asking us to do this work for you – Robin Dec 10 '12 at 07:21
  • Yeah, you're right, that was really lazy of me. I apologize. I cut out about 500 lines of code and updated the OP. Now the program is bare-bones, but the problem still exists – Alex Kibler Dec 10 '12 at 07:29
  • If you've tossed the profs advice to use AWT, change `class CanvasEX extends Canvas` to `class CanvasEX extends JPanel` & `public void paint(Graphics g) {..` to `public void paintComponent(Graphics g) { super.paintComponent(g);..` – Andrew Thompson Dec 10 '12 at 07:39
  • @AndrewThompson That actually sort of fixed the problem. I replaced the first two things (I don't actually have a super.paint(g); anywhere, which is weird, because I thought I did. Anyway, the weird thing now is that as soon as I draw something, it paints a duplicate of the JMenubar on the screen right under the JMenuBar – Alex Kibler Dec 10 '12 at 07:49
  • I undeleted my 'comment upgraded to answer' since it seemed it might not be relevant, but I tested the changes here and noticed an improvement - so (shrugs) I'll leave it as an answer. – Andrew Thompson Dec 10 '12 at 07:54
  • And when I applied that stuff to my program that was mostly working (minus clicking New), on launch the JFrame is only big enough to fit the menubar and nothing more – Alex Kibler Dec 10 '12 at 07:56

1 Answers1

3

If you've tossed the profs advice to use AWT, change

class CanvasEX extends Canvas

..to..

class CanvasEX extends JPanel

&

public void paint(Graphics g)
{
    .. 

to

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

Then you will need to figure how to get the drawings to persist.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Thanks for the help so far. Like I said in the comments above, it made the New button work, but now the window isn't its normal size even though I have the CanvasEX object set to 800x600, and the bounds of the JFrame set to 800x600 as well. And, yeah, there's that problem of getting the drawings to persist. I don't even know where to start since this is my first time working with Swing – Alex Kibler Dec 10 '12 at 08:01
  • Is this about custom painting of a **component**, or just custom painting? I'd tend to do the latter in a `BufferedImage` as shown [here](http://stackoverflow.com/a/13796268/418556). – Andrew Thompson Dec 10 '12 at 08:08
  • It's just about the custom painting in general. I thought what I was doing was basically a buffered image anyway. My whole update method in CanvasEX is just to buffer the image. Thanks again for all of the help. I've got to get to bed now (as it's 3:10AM here), but I'll check out your tutorial when I get up. It looks pretty sweet. – Alex Kibler Dec 10 '12 at 08:10