简体   繁体   English

如何从其他类更新JLabel?

[英]How do I update JLabel from antoher class?

I need to use a thread to change the position of my JLabel (movingDisplay) every second when I click on my button (btnDisplay) and for the thread to stop when I click on my other button (btnDStop). 当我单击按钮(btnDisplay)时,我需要使用一个线程来每秒更改JLabel(movingDisplay)的位置,并且当我单击其他按钮(btnDStop)时,该线程停止。 I have a class called MoveDisplay that implements Runnable and does this action when I click on btnDisplay. 我有一个名为MoveDisplay的类,该类实现Runnable并在单击btnDisplay时执行此操作。 After MoveDisplay has randomized x and y for my JLabel, it's supposed to send x and y back to my main class where it updates the position of the JLabel. 在MoveDisplay为我的JLabel随机分配了x和y之后,应该将x和y发送回我的主类,并在其中更新JLabel的位置。 I have a method in my mainclass to update the JLabel position however I get a NullPointerException when trying to do so. 我的主类中有一个方法可以更新JLabel位置,但是尝试这样做时会收到NullPointerException。 In fact it doesn't work changing any component at all from MoveDisplay class. 实际上,从MoveDisplay类更改任何组件根本不起作用。

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

MoveDisplay class: 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 class: 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);
 }

}

You have to get a reference to the existing GUIFrame instance instead of creating a new one, try this: 您必须获得对现有GUIFrame实例的引用,而不是创建一个新实例,请尝试以下操作:

MoveDisplay 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 GUIFrame

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

Also, you have to run the part of the code that changes the GUI on the EDT thread. 另外,您还必须运行部分代码以更改EDT线程上的GUI。

Is not a good idea to stop a thread by interrupting it, you can stop it by setting the moving variable to false . 通过中断线程来停止线程不是一个好主意,可以通过将moving变量设置为false来停止线程。

I've checked the code and in the MoveDisplay.run() you were creating a new frame, but in it's constructor the panel wasn't initialized, which triggered the NPE. 我检查了代码,并在MoveDisplay.run()中创建了一个新框架,但是在其构造函数中,面板未初始化,这触发了NPE。 Because of this I've refactored the GUIFrame constructor to initialeze all components (invoked the Start() method) and removed the new frame's initialization from the run method. 因此,我重构了GUIFrame构造函数以初始化所有组件(调用Start()方法),并从run方法中删除了新框架的初始化。 Here are the modified classed 这是修改后的分类

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

} }

And here is the new frame class 这是新的框架类

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

} }

Maybe you can also use the Singleton Pattern to get the original instance of GUIFrame : 也许您也可以使用Singleton Pattern获取GUIFrame的原始实例:

public static class instanceClassA { 
    private static instanceClassA = null; 

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM