自定义按钮'有时'导致空指针

时间:2016-02-14 18:23:38

标签: java button menu enums

到目前为止,我已经学习并试用了不到一个月的Java。我目前正在尝试更改枚举状态的自定义按钮(不是jbuttons)。 对于这个测试,我有两个类,它们都具有完全相同的代码(菜单和设置),除了按钮的名称和位置以及它们在点击时设置的状态。 奇怪的是,如果我将菜单作为起始状态,那么我总是在这行代码中得到一个空指针错误:

for(int i = 0; i < options.length; i++){
        if(options[i].intersects(new Rectangle(Mouse.getX(), Mouse.getY(), 1, 1))){
            currentSelection =i;
            clicked = Mouse.wasPressed(MouseEvent.BUTTON1);
        }
    }

但是如果设置是开始状态,那么我可以在两个按钮上来回点击,完全没有错误。 由于菜单和设置都具有相同的代码,因此我不知道为什么会出现此错误。

Bellow我将发布参与此按钮测试的课程,将来是否会更好地链接Github存储库而不是发布完整的类?

感谢您为解决这个谜团提供的任何帮助!

主类创建窗口并设置状态:

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;

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

private static int width = 800;
private static int height = 600;
public static String title ="<{[x]}>";

public static final boolean DEBUG = true;
private static Thread thread;
public static JFrame frame;
private static boolean running = false;
private Menu menu;
private Settings settings;

public static enum STATE{
    MENU, SETTINGS
};
public static STATE state = STATE.MENU;
/*----------------------------------------------------------------------------------------------------*/    
public static void main(String[] args){                                 
    Base base = new Base();
    Base.frame.setResizable(true);
    Base.frame.setTitle(Base.title);
    Base.frame.add(base);                                               
    Base.frame.pack();
    Base.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Base.frame.setLocationRelativeTo(null);
    Base.frame.setVisible(true);
    base.start();
}
/*----------------------------------------------------------------------------------------------------*/
public Base(){
    setPreferredSize(new Dimension(width, height));
    frame = new JFrame();
    settings = new Settings();
    menu = new Menu();
    Mouse mouse = new Mouse();
    addMouseListener(mouse);
    addMouseMotionListener(mouse);
}
/*----------------------------------------------------------------------------------------------------*/
public void update(){
    if(state == STATE.MENU){
        menu.tick();            
    }
    if(state == STATE.SETTINGS){
        settings.tick();
    }
}
/*----------------------------------------------------------------------------------------------------*/
public synchronized void start(){                                       
    running = true;
    thread = new Thread(this, "Display");
    thread.start();
}
/*----------------------------------------------------------------------------------------------------*/    
public synchronized static void stop(){                                     
    running = false;
    System.exit(0);
    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
/*----------------------------------------------------------------------------------------------------*/
public void render(){
    BufferStrategy bs = getBufferStrategy();
    if(bs == null){
        createBufferStrategy(3);
        return;
    }
    Graphics2D g = (Graphics2D) bs.getDrawGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, getWidth(), getHeight());
    ///////////////////////////////////////////////
    if(state == STATE.MENU){
        menu.init();
        menu.render(g);
    }
    if(state == STATE.SETTINGS){
        settings.init();
        settings.render(g);
    }
    ///////////////////////////////////////////////
    g.dispose();
    bs.show();
}
/*----------------------------------------------------------------------------------------------------*/    
public void run() {                         // The main game loop of the game.
    long lastTime = System.nanoTime();
    final double ns = 1000000000.0 / 60.0;
    long timer = System.currentTimeMillis();
    double delta = 0;
    int frames = 0;
    int updates = 0;
    requestFocus();
/*--------------------*/// Start of Game Loop.
    while(running){
        long now = System.nanoTime();
        delta += (now-lastTime) / ns;   // Ensures only 60 updates per second.
        lastTime = now;
/*--------------------*/    
        while (delta >=1){          // Bellow things to update 60 times a second.
            update();
            updates++;
            delta--;     
            }                       // Bellow things to update as fast as possible.
        render();
        frames++;
 /*--------------------*/               // Bellow sets the updates per second and fps to the title bar.         
        if(System.currentTimeMillis() - timer > 1000){
            timer +=1000;
            frame.setTitle(title + " | " + updates + " ups, " + frames + " fps");
            updates = 0;
            frames = 0;
        }
    }
 /*--------------------*/// End of Game Loop.
    stop();
    System.exit(0); 
}
 /*----------------------------------------------------------------------------------------------------*/
public static int getWindowWidth(){
    return width;
}
public static int getWindowHeight(){
    return height;
}
}

菜单类:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

public class Menu {

private Button[] options;
private int currentSelection;

public Menu(){  
}

public void init() {
    options = new Button[1];
    options[0] = new Button("Settings", 300 ,300, new Font("Arial", Font.PLAIN, 32), new Font("Arial", Font.BOLD, 48), Color.WHITE , Color.GREEN);
}

public void tick(){

    boolean clicked = false;

    for(int i = 0; i < options.length; i++){
        if(options[i].intersects(new Rectangle(Mouse.getX(), Mouse.getY(), 1, 1))){
            currentSelection =i;
            clicked = Mouse.wasPressed(MouseEvent.BUTTON1);
        }
    }
    if (clicked)    select();
}

private void select(){
switch(currentSelection){
case 0:
    Base.state = Base.STATE.SETTINGS;
    System.out.println("Settings");
    break;
}
}
/*----------------Render Method----------------------------------------------------------------*/   
public void render(Graphics2D g) {

for(int i = 0; i < options.length; i++){
    if(i == currentSelection)
        options[i].setSelected(true);
    else options[i].setSelected(false);

    options[i].render(g);
}
}

}

设置类:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

public class Settings {

private Button[] options;
private int currentSelection;

public Settings(){
}

public void init() {
    options = new Button[1];
    options[0] = new Button("Back",         300 ,200, new Font("Arial", Font.PLAIN, 32), new Font("Arial", Font.BOLD, 48), Color.WHITE , Color.GREEN);
}

public void tick(){

    boolean clicked = false;

    for(int i = 0; i < options.length; i++){
        if(options[i].intersects(new Rectangle(Mouse.getX(), Mouse.getY(), 1, 1))){
            currentSelection =i;
            clicked = Mouse.wasPressed(MouseEvent.BUTTON1);
        }
    }
    if (clicked)    select();
}

private void select(){
switch(currentSelection){
case 0:
    Base.state = Base.STATE.MENU;
    System.out.println("menu");
    break;
}
}
/*----------------Render Method----------------------------------------------------------------*/   
public void render(Graphics2D g){

for(int i = 0; i < options.length; i++){
    if(i == currentSelection)
        options[i].setSelected(true);
    else options[i].setSelected(false);

    options[i].render(g);
}
}

}

按钮类:

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;



@SuppressWarnings("serial")
public class Button extends Rectangle{

static int Width = Base.getWindowWidth();
static int Height = Base.getWindowHeight();

private Font font, selectedFont;
private Color color, selectedColor;
private boolean selected;
private String text;
private int textY;
private int textX;

public Button(String text, int textY, Font font, Font selectedFont, Color color, Color selectedColor) {
    this.text = text;
    this.textY = textY;
    this.font = font;
    this.selectedFont = selectedFont;
    this.color = color;
    this.selectedColor = selectedColor;
}

public Button(String text,int textX, int textY, Font font, Font selectedFont, Color color, Color selectedColor) {
    this.text = text;
    this.textX = textX;
    this.textY = textY;
    this.font = font;
    this.selectedFont = selectedFont;
    this.color = color;
    this.selectedColor = selectedColor;
}

public void setSelected(boolean selected) {
    this.selected = selected;
}

public void render(Graphics g){
    if(selected)
        Fonts.drawString(g, selectedFont, selectedColor, text, textX, textY);
    else
        Fonts.drawString(g, font, color, text,textX, textY);

    FontMetrics fm = g.getFontMetrics();
    this.x = textX;
    this.y = textY - fm.getHeight();
    this.width = fm.stringWidth(text);
    this.height = fm.getHeight();
    //g.drawRect(x, y, width, height);

}

}

字体类:

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;



public class Fonts {

static int width = Base.getWindowWidth();
static int height = Base.getWindowHeight();

public Fonts(){

}
/*--------------------------------------------------------------------------------*/
public static void drawString(Graphics g, Font f, Color c, String text, int x, int y){
    g.setColor(c);
    g.setFont(f);
    g.drawString(text, x, y);
}
/*--------------------------------------------------------------------------------*/    
public static void drawString(Graphics g, Font f, Color c, String text ){
    FontMetrics fm = g.getFontMetrics(f);

    int x = (width - fm.stringWidth(text))/2;
    int y = ((height - fm.getHeight())/2) + fm.getAscent();
    drawString(g, f, c, text, x, y);
}
/*--------------------------------------------------------------------------------*/
public static void drawString(Graphics g, Font f, Color c, String text, double x ){
    FontMetrics fm = g.getFontMetrics(f);

    int y = ((height - fm.getHeight())/2) + fm.getAscent();
    drawString(g, f, c, text, (int)x, y);
}
/*--------------------------------------------------------------------------------*/
public static void drawString(Graphics g, Font f, Color c, String text, int y ){
    FontMetrics fm = g.getFontMetrics(f);

    int x = (width - fm.stringWidth(text))/2;
    drawString(g, f, c, text, x, y);
}

}

鼠标类:

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class Mouse implements MouseListener, MouseMotionListener{

private static final int NUM_BUTTONS = 10;
private static final boolean buttons[] = new boolean[NUM_BUTTONS];
private static final boolean lastbuttons[] = new boolean[NUM_BUTTONS];
private static int mouseX = -1;
private static int mouseY = -1;
private static int mouseB = -1;



public static int getX(){
    return mouseX;
}
public static int getY(){
    return mouseY;
}

public static int getButton(){
    return mouseB;
}

@Override
public void mouseDragged(MouseEvent e) {
    mouseX = e.getX();
    mouseY = e.getY();
}

@Override
public void mouseMoved(MouseEvent e) {
    mouseX = e.getX();
    mouseY = e.getY();
}

@Override
public void mouseClicked(MouseEvent e) {
}

@Override
public void mouseEntered(MouseEvent e) {
}

@Override
public void mouseExited(MouseEvent e) {
}

@Override
public void mousePressed(MouseEvent e) {
    mouseB = e.getButton();
    buttons[e.getButton()] = true;

}

@Override
public void mouseReleased(MouseEvent e) {
    mouseB = MouseEvent.NOBUTTON;
    buttons[e.getButton()] = false;

}

public static void update(){
    for(int i = 0; i < NUM_BUTTONS; i++)
        lastbuttons[i] = buttons[i];
}

public static boolean isDown(int button){
    return buttons[button];
}

public static boolean wasPressed(int button){
    return isDown(button) && !lastbuttons[button];
}

public static boolean wasReleased (int button){
    return !isDown(button) && lastbuttons[button];
}

}

1 个答案:

答案 0 :(得分:1)

在调用init()之前,Menu和Settings类中的选项数组最初为null,并且没有给出有效的引用。您是否在调用方法之前尝试访问数组?考虑先修复它。也许init代码需要成为类的构造函数的一部分?

其他建议:

  • 您的Mouse类具有状态,因此所有静态代码都应该是实例代码。
  • 另一方面,字体类看起来像是一个&#34;实用程序&#34; class,一个没有状态,也没有设置或改变状态的方法,所以静态方法似乎没问题。
  • 您的Button类与java.awt.Button名称冲突。为避免混淆他人或未来的自我,请考虑将其名称更改为与核心Java类不匹配的名称。
  • 不是每次调用Button的渲染时重新绘制,而是考虑使用延迟启动策略创建和存储BufferedImages然后显示。
  • 您的游戏循环似乎没有遵循Swing线程规则,这可能会导致间歇性且难以调试的异常被抛出。
  • 你好像把AWT和Swing混在一起,如果你不小心的话,这是一件很危险的事情。