当我点击我的按钮(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);
}
}
答案 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;
}
}