[英]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.