如何使用Java2D在GUI中使用ActionListener调用方法

时间:2012-11-25 23:47:12

标签: java user-interface graphics actionlistener

我正在用Java编写一个实现ActionListener的图形用户界面程序。该程序是使用2D图形的吉他和弦可视化器。我有一个工具栏,用户可以选择要显示的和弦。因此在actionPerformed(ActionEvent e)方法中,当用户选择某个和弦时,该选项会调用显示和弦的方法。但是,当我测试程序时,我遇到了大量的错误。以下是错误消息

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)

另外,我没有使用JPanel或JFrame。我只是使用Frame。 我的计划有什么问题?谢谢!

以下是我的一些代码(截至目前,该程序已超过500行)。

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();
}

2 个答案:

答案 0 :(得分:2)

啊哈,投射变量,null,图形,我要猜测 - 你试图将Graphics对象保存为类字段,你将它转换为Graphics2D,它是null。如果是这样,你会想要了解如何使用Swing绘图,因为这不是它的完成方式。您必须使用JVM提供的Graphics对象并将其传递给JComponent(例如JPanel的)paintComponent(Graphics g)方法。这是开始在Swing中学习Performing Custom Painting的一个不错的链接。

同样,你会想要重构你的代码,因为你的类听起来方式太大了。您还需要学习和使用Java命名约定。例如,类名应以大写字母开头。

哎呀,情况更糟:

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...

你正在使用一个null的变量,所以它抛出一个NPE就不足为奇了。请阅读我链接到的教程。

您需要在JPanel或其他JComponent派生类的paintComponent(...)方法覆盖中进行绘制,或者在BufferedImage中通过提取其Graphics对象并使用它进行绘制。如果您正在创建静态图像(如和弦选项卡),那么BufferedImages可能会成为可行的方式,然后将它们显示在JLabel或paintComponent方法中的ImageIcon中。

答案 1 :(得分:2)

您对此的期望是什么:

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

此外,您的paint方法违反了自定义绘画最重要的规则之一,它无法调用super.paint这会产生更多问题,因此值得列出。

执行自定义绘制时要覆盖的首选方法是paintComponent,但是,因为您覆盖了Frame(??),所以它没有paintComponent方法。

这是一些想法......

  1. 在AWT上使用Swing组件。它们更容易使用。
  2. JPanel等内容扩展并在其上执行自定义绘画。这为您提供了更灵活的设计选择,并减少了问题。
  3. 如果你不这样做,请随时致电super.paintXxx,希望事情能够在你脸上爆炸。
  4. 所有绘画必须使用paint方法完成。你无法控制油漆过程,只需接受它并继续前进。您可以鼓励重绘,但您只能在paint方法的上下文中进行绘制。
  5. Graphics上下文由系统控制。如果要在其上绘画,则必须等待其中一个可用,请参阅上一点。这个上下文可以改变,所以你永远不应该保持对它的引用。共享Graphics上下文,未能遵守绘制链将导致出现绘制工件
  6. 您可能希望抽出时间阅读