【问题标题】:Basic Java Gui Error: Why is the JButton causing errors?基本 Java Gui 错误:为什么 JButton 会导致错误?
【发布时间】:2014-10-30 01:48:55
【问题描述】:

我的代码可以编译并且看起来运行良好,直到我点击了 JButton,然后我得到了很多错误。我不确定我做错了什么。代码应该做的是出现一个窗口,并在单击按钮时随机显示两个骰子图像。图片和我的程序在同一个目录下,它们被命名为 1-6。

代码如下:

import java.lang.Math;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DiceSimulator extends JFrame
{
  private JLabel dieOne;
  private JLabel dieTwo;
  public DiceSimulator()
  {
    setTitle("Dice Simulator");
    JLabel dieOne, dieTwo;
    dieOne = new JLabel();
    dieTwo = new JLabel();
    JButton button = new JButton("Roll the Dice");
    button.addActionListener(new buttonListener());  
    setLayout(new BorderLayout());
    JPanel panel = new JPanel();
    panel.add(button, BorderLayout.SOUTH);
    panel.add(dieOne);
    panel.add(dieTwo);
    add(panel);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
    setVisible(true);
    }
  private class buttonListener implements ActionListener
  {
    public void actionPerformed(ActionEvent e)
    {
      ImageIcon one = new ImageIcon("1.jpg"); 
      ImageIcon two = new ImageIcon("2.jpg"); 
      ImageIcon three = new ImageIcon("3.jpg"); 
      ImageIcon four = new ImageIcon("4.jpg"); 
      ImageIcon five = new ImageIcon("5.jpg"); 
      ImageIcon six = new ImageIcon("6.jpg"); 
      int firstRoll = (int)(Math.random()*6)+1;
      int secondRoll = (int)(Math.random()*6)+1;
      switch(firstRoll)
      {
        case 1: dieOne.setIcon(one);
        dieOne.setText(null);
        break;
        case 2: dieOne.setIcon(two);
        dieOne.setText(null);
        break;
        case 3: dieOne.setIcon(three);
        dieOne.setText(null);
        break;
        case 4: dieOne.setIcon(four);
        dieOne.setText(null);
        break;
        case 5: dieOne.setIcon(five);
        dieOne.setText(null);
        break;
        case 6: dieOne.setIcon(six);
        dieOne.setText(null);
        break;
      }
      switch(secondRoll)
      {
        case 1: dieTwo.setIcon(one);
        dieTwo.setText(null);
        break;
        case 2: dieTwo.setIcon(two);
        dieTwo.setText(null);
        break;
        case 3: dieTwo.setIcon(three);
        dieTwo.setText(null);
        break;
        case 4: dieTwo.setIcon(four);
        dieTwo.setText(null);
        break;
        case 5: dieTwo.setIcon(five);
        dieTwo.setText(null);
        break;
        case 6: dieTwo.setIcon(six);
        dieTwo.setText(null);
        break;
      }
    }
  }
  public static void main(String[] args)
  {
    new DiceSimulator();
  }
}

这是我点击按钮时遇到的错误:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at DiceSimulator$buttonListener.actionPerformed(DiceSimulator.java:57)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

【问题讨论】:

  • 阅读例外情况 - 他们不仅会为您提供所有您知道的有趣信息,它实际上是一个关键的诊断工具。在您的情况下,DiceSimulator.java 的第 57 行的某些内容为空
  • 我不知道怎么读,我是初学者,如果是其他方式我不会有这个问题。
  • 第 57 行是哪一行?
  • dieOne.setText(null);在我的第一个开关的案例 6 下。不过我不明白这有什么关系。

标签: java user-interface logic runtime-error


【解决方案1】:

我认为您生成的随机数不正确。当我运行类似的代码来生成随机数时,我会在随机数中包含一堆零,而你的 switch 语句无法处理这些零。

为了安全起见,导入 java.util.Random 包,然后创建一个类似的对象

导入 java.util.Random;

public class testRandom{

  public static void main (String [] args){
    Random rg = new Random();
   int x;
   for(int i = 0; i < 100; i++){
    x = rg.nextInt(6) + 1;
    System.out.println(x);
   }

  }


}

更新

您真正想要实现 JFrame 的方式是拥有一个构造 JPanel 然后由 main 方法调用的构造方法。查看creating JFrame applications 的 Java 教程中的示例程序是如何设置的——那里有一些很好的示例代码,说明您希望如何构建程序。

如果您将程序更改为示例中的结构,我使用静态 JLabel 声明的原因将是不必要的,但本质上,如果您声明一个类变量,如 JLabel,则构造的每个类实例这些变量会有自己的版本。因此,当您在构造函数之外有一个方法时,您将不会使用相同的 JLabel,即使它们具有相同的名称 - 如果您重新编写程序,所有这些都将无关紧要。

当您构建一个新对象时,可以完成接口的匿名实现。对于动作监听器,它看起来像:

JButton button = new JButton("Click me!");
button.addActionListener(new ActionListener(){
   public void (ActionPerformed ap){
     //DO SOMETHING ON CLICK
  }
});

我怀疑您收到错误的原因是因为您的 actionListener 没有处理调用构造函数时创建的相同 JLabels - 这就是为什么我会尝试变量的静态声明,或者接口的匿名实现

【讨论】:

  • 我确实忘记偏移 1。我已经更正了代码。 int firstRoll = (int)(Math.random()*6)+1;等
  • 我的另一个建议是将你的 JLabels 声明为静态的,如果这不能解决问题
  • 另外,您可能需要考虑在 diceRoller 构造函数中匿名实现动作监听器
  • 您介意解释一下您为什么要这样做吗?另外,匿名是什么意思?
  • 我会将其添加到答案中
【解决方案2】:

当我运行代码时,它会在更改图标时引发异常。看起来您正在加载的图像在那里不存在。尝试找出您的相对路径是什么,或者使用绝对路径进行测试。

如果您需要更多解释,请写评论。

希望我能帮上忙。

编辑

更多解释:

应用程序“运行”在硬盘驱动器上的特定位置,说起来很简单 :D 你想加载图片。由于您给他的路径不是以斜线开头,因此它将它们解释为相对路径。这意味着,他在执行目录中查找图像。当它以“/”开头时,他将其解释为从您的硬盘驱动器开始的绝对路径。

Here 解释了如何获取执行目录。只需使用

System.out.println(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath());

创建对象并检查启动程序时控制台输出的内容。在名为那里的文件夹中,您必须放置图片。不建议这样做,但为了测试它的工作原理。

编辑 2

没注意:

这里有 JLabels dieOne 和 dieTwo:

private JLabel dieOne;
private JLabel dieTwo;

这些是“全局”变量,可以在方法中被同名的局部变量隐藏。那是你犯错的地方。你写:

public DiceSimulator() {
    setTitle("Dice Simulator");
    JLabel dieOne, dieTwo;
    [...]

您在此处隐藏了“全局”dieOne 和 dieTwo,因为您声明了具有相同名称的本地。但它们不是必需的,因为您想要初始化“全局”JLabels。当你现在这样做时,构造函数中的 dieOne 和 dieTwo 在完成实例化对象时被破坏,并且“全局”没有值 => 当尝试更改文本时,它们没有导致 NullPointerException 的地址。只需删除

JLabel dieOne, dieTwo;

一切都应该可以。

最后希望一切都清楚了,我可以帮忙。

【讨论】:

  • 感谢您一开始就没有粗鲁。我的电脑上有图片,所以它们应该正在加载,如果你是这个意思的话。
  • 应用程序运行在硬盘驱动器上的特定位置,说起来很简单 :D 你想加载图片。由于您给他的路径不是以斜线开头,因此它将它们解释为相对路径。这意味着,他在执行目录中查找图像。当它以 / 开头时,他将其解释为从您的硬盘驱动器开始的绝对路径。只是问它是否不够清楚:D
  • 图片如果和运行的程序在同一个文件夹里,就在执行目录,对吗?
  • 查看我编辑的答案并检查您认为的目录是否真的是执行目录。
  • 我将它定向到图像,不幸的是没有运气。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 2020-07-16
  • 2014-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多