JT9
JT9

Reputation: 944

How to call a method using ActionListener in GUI using Java2D

I am writing a graphical user interface program in Java that implements ActionListener. The program is a guitar chord visualizer using 2D graphics. I have a toolbar where the user selects what chord to be displayed. So in the actionPerformed(ActionEvent e) method, when the user selects a certain chord, that choice calls a method where the chord is displayed. However, when I test the program I get tons of errors. Here are the error messages

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at fretboard.displayAMajor(fretboard.java:493)
    at fretboard.actionPerformed(fretboard.java:74)
    at java.awt.MenuItem.processActionEvent(MenuItem.java:650)
    at java.awt.MenuItem.processEvent(MenuItem.java:609)
    at java.awt.MenuComponent.dispatchEventImpl(MenuComponent.java:343)
    at java.awt.MenuComponent.dispatchEvent(MenuComponent.java:331)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707)
    at java.awt.EventQueue.access$400(EventQueue.java:82)
    at java.awt.EventQueue$2.run(EventQueue.java:663)
    at java.awt.EventQueue$2.run(EventQueue.java:661)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
    at java.awt.EventQueue$3.run(EventQueue.java:677)
    at java.awt.EventQueue$3.run(EventQueue.java:675)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:674)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Also, I am not using JPanel or JFrame. I am simply using Frame. What is wrong with my program? Thanks!

Here is some of my code (The program is over 500 lines as of now).

public class fretboard extends Frame implements ActionListener{
    public static void main(String[] args) {
        Frame frame = new fretboard();
        frame.setSize(1280, 960);
        frame.setVisible(true);
    }


    /**
     * Create the menu bar and set title
     */

    public fretboard() {
        // Change the title of the window
        setTitle("Fretboard");
        // Create a menu bar where user will be given choice of chords
        MenuBar mb = new MenuBar();
        setMenuBar(mb);
        Menu menu = new Menu("Chords");
        mb.add(menu);
     }

    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        if("A Major".equals(command)) {
            displayAMajor();
        }
This method contains the bulk of my program. Here are just a few lines.

    public void paint(Graphics g) {
        // Declare local variables
        int h = 40, w = 26, x = 695, y = 230;
        Graphics2D g2 = (Graphics2D) g;
        Font font = new Font("SansSerif", Font.BOLD, 28);
        Font font1 = new Font("SansSerif", Font.BOLD, 18);          
        // Declare the note variables
        // First string
        Ellipse2D E1 = new Ellipse2D.Double(x, y-110, w, h);
        // Open the image
        File fretBoardFile = new File("/Users/macbook/desktop/Gibson_Fretboard.jpg");
        BufferedImage bi = null;
        try {
            bi = ImageIO.read(fretBoardFile);
            g.drawImage(bi, 25, 25, null);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // Draw notes
        // Draw the E note on the open 1st string
        // Change color to blue
        g2.setColor(Color.blue);
        g2.draw(E1);
        g2.fill(E1);
        g2.setColor(Color.white);
        g2.setFont(font);
        g2.drawString("E", x+5, y-80);
        // Change color back to blue
        g2.setColor(Color.blue);

public void displayAMajor() {
    // Declare local variables
    int h = 40, w = 26, x = 695, y = 230;
    Graphics g = null;
    Graphics2D g2 = (Graphics2D) g;
    //Graphics2D g2 = new Graphics();
    Font font = new Font("SansSerif", Font.BOLD, 28);
    // Declare notes
    Ellipse2D E1 = new Ellipse2D.Double(x, y-110, w, h);
    // Display notes for the A Major chord
    // Draw the E note on the open 1st string
    // Change color to red
    g2.setColor(Color.red);
    g2.draw(E1);
    g2.fill(E1);
    g2.setColor(Color.white);
    g2.setFont(font);
    g2.drawString("E", x+5, y-80);
    // Change color back to blue
    g2.setColor(Color.blue);
    repaint();
}

Upvotes: 2

Views: 901

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347234

Just what did you expect from:

Graphics g = null;
Graphics2D g2 = (Graphics2D) g;

Also, your paint method breaks one of the most important rules of custom painting, it fails to call super.paint this is going to create more problems then it is worth listing.

The preferred method to override when performing custom painting is paintComponent, but, because you're overriding Frame (??) it doesn't have a paintComponent method.

Here's some ideas...

  1. Use Swing components over AWT. They're easier to use.
  2. Extend from something like JPanel and perform your custom painting on it instead. This provides you with more flexible design choices and cause less issues.
  3. Always call super.paintXxx, if you don't, expect things to blow up in your face.
  4. All painting MUST be done from the a paint method. You do not control over the paint process, just accept it and move on. You can encourage a repaint, but you must only paint from within the context of a paint method.
  5. The Graphics context is controlled by the system. If you want to paint on it, you must wait for one to become available, see previous point. This context can change, so you should never maintain a reference to it. The Graphics context is shared, failing to honor the paint chain will result in paint artifacts appearing

You might like to make the time to have a read through

Upvotes: 2

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Aha, casting variables, null, graphics, I'm going to take a guess -- you're trying to save the Graphics object as a class field, you're casting it to Graphics2D, and it's null. If so, you'll want to read up on how to do drawing with Swing because that's not how it's done. You must use the Graphics object provided by the JVM and passed into a JComponent's (such as a JPanel's) paintComponent(Graphics g) method. This is a decent link to start learning about Performing Custom Painting in Swing.

And again, you'll want to refactor your code because your class sounds way too big. Also you'll want to learn and use Java naming conventions. Class names should start with upper case letters for instance.

Yikes, it's even worse:

Graphics g = null;  // *******  this is null!!!!
Graphics2D g2 = (Graphics2D) g;  // ***** it's *STILL* null!!
//Graphics2D g2 = new Graphics();
Font font = new Font("SansSerif", Font.BOLD, 28);
Ellipse2D E1 = new Ellipse2D.Double(x, y-110, w, h);
g2.setColor(Color.red);   // ***** it's *STILL* null!!
g2.draw(E1);   // ***** it's *STILL* null!!
g2.fill(E1); // **** etc...

You're using a variable that is null, so it should be no surprise that it throws a NPE. Please read the tutorial that I've linked to.

You'll want to do your drawing either in the paintComponent(...) method override of a JPanel or other JComponent-derived class, either that or in a BufferedImage by extracting its Graphics object and drawing with that. If you're creating static images such as chord tabs, then BufferedImages will likely be the way to go, and then display them either in a ImageIcon held in a JLabel or in a paintComponent method.

Upvotes: 2

Related Questions