java - 如何从另一个类更新JLabel的?

标签 java multithreading class jframe jpanel

单击按钮(btnDisplay)时,我需要使用一个线程每秒更改JLabel(movingDisplay)的位置,单击另一个按钮(btnDStop)时,该线程停止运行。我有一个名为MoveDisplay的类,该类实现Runnable并在单击btnDisplay时执行此操作。在MoveDisplay为我的JLabel随机分配了x和y之后,应该将x和y发送回我的主类,并在其中更新JLabel的位置。我的主类中有一个方法可以更新JLabel位置,但是尝试这样做时会收到NullPointerException。实际上,从MoveDisplay类更改任何组件根本不起作用。

public class Main {
    public static void main(String[] args) {
        GUIFrame test = new GUIFrame();
    }
}

MoveDisplay类:
public class MoveDisplay implements Runnable {
 private GUIFrame gui;
 private boolean moving = true;
 private Thread thread;

 public void run() {
  gui = new GUIFrame();
  if (moving) {
   Random rand = new Random();
   while (moving) {
    int x = rand.nextInt(150) + 1;
    int y = rand.nextInt(150) + 1;
    gui.moveDisplay(x, y, 100, 100);
    try {
     thread.sleep(1000);
    } catch (InterruptedException e) {
     break;
    }
   }
  }
 }

 public void start() {
  thread = new Thread(new MoveDisplay());
  thread.start();
 }

 public void stop() {
  thread.interrupt();
  System.out.println("Stopped");
 }
}

GUIFrame类:
public class GUIFrame {

 private JFrame frame; // The Main window
 private JLabel movingDisplay;
 private boolean playing = true;
 private boolean moving = true;
 private MoveDisplay moveDisplay = new MoveDisplay();

 /**
  * Starts the application
  */
 public void Start() {
  frame = new JFrame();
  frame.setBounds(0, 0, 494, 437);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setLayout(null);
  frame.setTitle("Multiple Thread Demonstrator");
  InitializeGUI(); // Fill in components
  frame.setVisible(true);
  frame.setResizable(false); // Prevent user from change size
  frame.setLocationRelativeTo(null); // Start middle screen
 }

 public void InitializeGUI() {

  // The moving display outer panel
  JPanel pnlDisplay = new JPanel();
  Border b2 = BorderFactory.createTitledBorder("Display Thread");
  pnlDisplay.setBorder(b2);
  pnlDisplay.setBounds(12, 118, 222, 269);
  pnlDisplay.setLayout(null);

  // Add buttons and drawing panel to this panel
  btnDisplay = new JButton("Start Display");
  btnDisplay.setBounds(10, 226, 121, 23);
  pnlDisplay.add(btnDisplay);

  btnDStop = new JButton("Stop");
  btnDStop.setBounds(135, 226, 75, 23);
  pnlDisplay.add(btnDStop);

  pnlMove = new JPanel();
  pnlMove.setBounds(10, 19, 200, 200);
  Border b21 = BorderFactory.createLineBorder(Color.black);
  pnlMove.setBorder(b21);
  pnlDisplay.add(pnlMove);
  // Then add this to main window
  frame.add(pnlDisplay);

  movingDisplay = new JLabel("DisplayThread");
  pnlMove.add(movingDisplay);
  btnDStop.setEnabled(false);

  btnDisplay.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent arg0) {
    moving = true;
    btnDisplay.setEnabled(false);
    btnDStop.setEnabled(true);
    startMoveDisplay();
   }
  });

  btnDStop.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent arg0) {
    moving = false;
    btnDisplay.setEnabled(true);
    btnDStop.setEnabled(false);
    startMoveDisplay();
   }
  });
 }

 public void startMoveDisplay() {
  if(moving) {
   moveDisplay.start();
  }
  else {
   moveDisplay.stop();
  }
 }


 public void moveDisplay(int x, int y, int a, int b) {
  movingDisplay.setBounds(10,10,150,150);
 }

}

最佳答案

我检查了代码,并在MoveDisplay.run()中创建了一个新框架,但是在其构造函数中,面板未初始化,这触发了NPE。正因为如此,我重构了GUIFrame构造函数initialeze所有组件(调用Start()方法)和run方法去除新的帧的初始化。下面是修改后的归类

public class MoveDisplay {
private GUIFrame gui;
private volatile boolean moving;

public MoveDisplay(GUIFrame gui) {
    this.gui = gui;
}

public void start() {
    moving = true;
    Random rand = new Random();
    while (moving) {
        int x = rand.nextInt(150) + 1;
        int y = rand.nextInt(150) + 1;
        gui.moveDisplay(x, y, 100, 100);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public void stop() {
    moving = false;
}

}

这是新的框架类
public class GUIFrame {

private JFrame frame; // The Main window
private JLabel movingDisplay;
private boolean playing = true;
private boolean moving = true;
private MoveDisplay moveDisplay;

public GUIFrame() {
    Start();
}

/**
 * Starts the application
 */
private void Start() {
    frame = new JFrame();
    frame.setBounds(0, 0, 494, 437);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(null);
    frame.setTitle("Multiple Thread Demonstrator");
    InitializeGUI(); // Fill in components
    frame.setVisible(true);
    frame.setResizable(false); // Prevent user from change size
    frame.setLocationRelativeTo(null); // Start middle screen

    moveDisplay = new MoveDisplay(this);
}

public void InitializeGUI() {

    // The moving display outer panel
    JPanel pnlDisplay = new JPanel();
    Border b2 = BorderFactory.createTitledBorder("Display Thread");
    pnlDisplay.setBorder(b2);
    pnlDisplay.setBounds(12, 118, 222, 269);
    pnlDisplay.setLayout(null);

    // Add buttons and drawing panel to this panel
    JButton btnDisplay = new JButton("Start Display");
    btnDisplay.setBounds(10, 226, 121, 23);
    pnlDisplay.add(btnDisplay);

    JButton btnDStop = new JButton("Stop");
    btnDStop.setBounds(135, 226, 75, 23);
    pnlDisplay.add(btnDStop);

    JPanel pnlMove = new JPanel();
    pnlMove.setBounds(10, 19, 200, 200);
    Border b21 = BorderFactory.createLineBorder(Color.black);
    pnlMove.setBorder(b21);
    pnlDisplay.add(pnlMove);
    // Then add this to main window
    frame.add(pnlDisplay);

    movingDisplay = new JLabel("DisplayThread");
    pnlMove.add(movingDisplay);
    btnDStop.setEnabled(false);

    btnDisplay.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            moving = true;
            btnDisplay.setEnabled(false);
            btnDStop.setEnabled(true);
            startMoveDisplay();
        }
    });

    btnDStop.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            moving = false;
            btnDisplay.setEnabled(true);
            btnDStop.setEnabled(false);
            startMoveDisplay();
        }
    });
}

public void startMoveDisplay() {
    if(moving) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                moveDisplay.start();
            }
        }).start();
    } else {
        moveDisplay.stop();
    }
}

public void moveDisplay(int x, int y, int a, int b) {
    movingDisplay.setBounds(x, y, a, b);
}

}

关于java - 如何从另一个类更新JLabel的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33692435/

相关文章:

java - 如何处理通过 Scala/Java ProcessBuilder 发送的 SSH 命令上的空格?

c# - Task.Yield - 实际用途?

python - I/O 密集型串行端口应用程序 : Porting from Threading, 基于队列的异步设计(ala Twisted)

c++ - 从叶类继承

java - 编译并运行Java,具有捆绑的依赖项

java - 测试 SNMP 连接可用性

java - 什么时候加载类?

multithreading - 使用boost的SSL asio代码,async_write_some挂起

c++ - 函数在 C++ 中返回一个结构?

c++ - 自定义链表使用具有链表的结构创建 RtlValidateHeap 错误