如何从antoher类更新JLabel?

时间:2015-11-13 12:08:14

标签: java multithreading class jframe jpanel

当我点击我的按钮(btnDisplay)时,我需要使用一个线程来改变我的JLabel(movingDisplay)的位置,当我点击我的另一个按钮(btnDStop)时,我需要停止线程。我有一个名为MoveDisplay的类,它实现了Runnable并在我点击btnDisplay时执行此操作。在MoveDisplay为我的JLabel随机化x和y之后,它应该将x和y发送回我的主类,在那里它更新JLabel的位置。我在我的mainclass中有一个方法来更新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);
 }

}

3 个答案:

答案 0 :(得分:0)

您必须获取对现有GUIFrame实例的引用,而不是创建新实例,请尝试以下操作:

MoveDisplay

public class MoveDisplay implements Runnable {
    private GUIFrame gui;
    Random rand = new Random();
    volatile boolean moving;

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

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

   public void stop() {
      moving = false;
   }
}

GUIFrame

public class GUIFrame{
   MoveDisplay moveDisplay = new MoveDisplay(this);
   ...
}

此外,您必须运行在EDT线程上更改GUI的部分代码。

通过中断线程停止线程不是一个好主意,您可以通过将moving变量设置为false来停止线程。

答案 1 :(得分:0)

我已经检查了代码,并且在MoveDisplay.run()中你正在创建一个新框架,但是在它的构造函数中,面板没有被初始化,这触发了NPE。因此,我重构了GUIFrame构造函数以初始化所有组件(调用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);
}

}

答案 2 :(得分:0)

也许您也可以使用Singleton Pattern来获取GUIFrame的原始实例:

public static class instanceClassA { 
    private static instanceClassA = null; 

    public static instanceClassA(){ 
        if(instance == null){
            instance = instanceClassA();
        }
        return instance;
    }
}