如何让 Java 程序在侦听器工作时等待?
How to make Java program wait while a listener is working?
我的程序中有一个 JSlider。当滑块的值改变时,程序会做一些事情。我想要做的是将滑块的值增加到它的最大值,每次滑块值增加时我都需要等待我在 ChangeListener class.
中所做的事情
这是我的相关代码(svPlay就像一个播放按钮):
this.svPlay.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for(int i=slider.getValue()+1;i<=slider.getMaximum();i++){
slider.setValue(i);
try{
Thread.sleep(1000);
}catch (Exception ex){
ex.printStackTrace();
}
}
}
});
问题是,例如,如果 i=10,则程序等待 10*1000(我使用 sleep() 方法的毫秒数),它会同时执行所有 changeListener 作业。
在 slider.setValue(i) 之后,changeListener 必须工作,然后程序应该休眠 1000 毫秒。我该怎么做?
编辑:这就是我根据上面的代码更改程序的方式。但是现在更改滑块值和滑块 "freezes".
时什么也没有发生
this.slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
new Thread(() -> {
try {
synchronized (lock) {
Thread.sleep(1234);
if(checkBox.isSelected()){
CyApplicationManager manager = adapter.getCyApplicationManager();
CyNetworkView networkView = manager.getCurrentNetworkView();
CyNetwork network = networkView.getModel();
CyTable table = network.getDefaultNodeTable();
FilterUtil filter = new FilterUtil(network,table);
ArrayList<CyNode> activities = filter.FilterRowByNodeType("activity", "nodeType");
CyColumn timeColumn = table.getColumn("startTime"); // Getting start time column
List<String> timeList = filter.getTimeFromColumn(timeColumn); // Gets value of start time column without null value
sliderVisualization.sortActivityTimes(timeList, activities);
sliderLabel.setText(timeList.get(slider.getValue()));
sliderVisualization.hideFutureNodes(timeList, filter, network, networkView);
networkView.updateView();
}
lock.notify();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}).start();
}
});
this.svPlay.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Thread(() -> {
slider.setEnabled(false);
for(int i=slider.getValue()+1;i<=slider.getMaximum();i++){
synchronized (lock) {
slider.setValue(i);
try {
lock.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
slider.setEnabled(true);
}).start();
}
});
我在 addChangeListener 方法中的 Thread.sleep() 之前和之后放置了 if 语句,但这两种方式都不起作用。我不知道我转换得好不好。你能帮我看看这段代码吗?
这是我从您的问题中了解到的:您在 Slider 更改侦听器中进行了长时间的计算。您想要对一系列值执行计算,并将其反映在滑块上。
如果上述前提是正确的,您不想在计算进行时休眠 n 秒——您想等待它们完成并尽快继续。一种方法是在锁上使用等待和通知命令(注意,最近的 Java 带有 java.util.concurrent 包,它包含更高级别的多线程控制,我认为使用起来会更好,但是我自己也不熟悉)
package testas;
import javax.swing.*;
public class Slider {
static class View {
public JPanel panel;
public JSlider slider;
public JButton button;
public JTextField tf;
public View() {
panel = new JPanel();
button = new JButton("a");
slider = new JSlider();
tf = new JTextField(4);
panel.add(button);
panel.add(slider);
panel.add(tf);
}
}
static class Controller {
private Object lock;
private View view;
public Controller() {
lock = new Object();
}
private synchronized void buttonHandler() {
new Thread(() -> {
view.slider.setEnabled(false);
for(int i=view.slider.getValue()+1;i<=view.slider.getMaximum();i++){
synchronized (lock) {
view.slider.setValue(i);
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
view.slider.setEnabled(true);
}).start();
}
private synchronized void sliderChangeHandler(int value) {
new Thread(() -> {
try {
synchronized (lock) {
Thread.sleep(1234);//some long calculations
view.tf.setText(String.valueOf(value));
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
public void setView(View v) {
view = v;
v.button.addActionListener(l -> buttonHandler());
v.slider.addChangeListener(l -> {
JSlider slider = (JSlider) l.getSource();
if (!slider.getValueIsAdjusting())
sliderChangeHandler(slider.getValue());
});
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Controller c = new Controller();
View v = new View();
c.setView(v);
JFrame f = new JFrame();
f.add(v.panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
});
}
}
我的程序中有一个 JSlider。当滑块的值改变时,程序会做一些事情。我想要做的是将滑块的值增加到它的最大值,每次滑块值增加时我都需要等待我在 ChangeListener class.
中所做的事情这是我的相关代码(svPlay就像一个播放按钮):
this.svPlay.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for(int i=slider.getValue()+1;i<=slider.getMaximum();i++){
slider.setValue(i);
try{
Thread.sleep(1000);
}catch (Exception ex){
ex.printStackTrace();
}
}
}
});
问题是,例如,如果 i=10,则程序等待 10*1000(我使用 sleep() 方法的毫秒数),它会同时执行所有 changeListener 作业。
在 slider.setValue(i) 之后,changeListener 必须工作,然后程序应该休眠 1000 毫秒。我该怎么做?
编辑:这就是我根据上面的代码更改程序的方式。但是现在更改滑块值和滑块 "freezes".
时什么也没有发生this.slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
new Thread(() -> {
try {
synchronized (lock) {
Thread.sleep(1234);
if(checkBox.isSelected()){
CyApplicationManager manager = adapter.getCyApplicationManager();
CyNetworkView networkView = manager.getCurrentNetworkView();
CyNetwork network = networkView.getModel();
CyTable table = network.getDefaultNodeTable();
FilterUtil filter = new FilterUtil(network,table);
ArrayList<CyNode> activities = filter.FilterRowByNodeType("activity", "nodeType");
CyColumn timeColumn = table.getColumn("startTime"); // Getting start time column
List<String> timeList = filter.getTimeFromColumn(timeColumn); // Gets value of start time column without null value
sliderVisualization.sortActivityTimes(timeList, activities);
sliderLabel.setText(timeList.get(slider.getValue()));
sliderVisualization.hideFutureNodes(timeList, filter, network, networkView);
networkView.updateView();
}
lock.notify();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}).start();
}
});
this.svPlay.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Thread(() -> {
slider.setEnabled(false);
for(int i=slider.getValue()+1;i<=slider.getMaximum();i++){
synchronized (lock) {
slider.setValue(i);
try {
lock.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
slider.setEnabled(true);
}).start();
}
});
我在 addChangeListener 方法中的 Thread.sleep() 之前和之后放置了 if 语句,但这两种方式都不起作用。我不知道我转换得好不好。你能帮我看看这段代码吗?
这是我从您的问题中了解到的:您在 Slider 更改侦听器中进行了长时间的计算。您想要对一系列值执行计算,并将其反映在滑块上。
如果上述前提是正确的,您不想在计算进行时休眠 n 秒——您想等待它们完成并尽快继续。一种方法是在锁上使用等待和通知命令(注意,最近的 Java 带有 java.util.concurrent 包,它包含更高级别的多线程控制,我认为使用起来会更好,但是我自己也不熟悉)
package testas;
import javax.swing.*;
public class Slider {
static class View {
public JPanel panel;
public JSlider slider;
public JButton button;
public JTextField tf;
public View() {
panel = new JPanel();
button = new JButton("a");
slider = new JSlider();
tf = new JTextField(4);
panel.add(button);
panel.add(slider);
panel.add(tf);
}
}
static class Controller {
private Object lock;
private View view;
public Controller() {
lock = new Object();
}
private synchronized void buttonHandler() {
new Thread(() -> {
view.slider.setEnabled(false);
for(int i=view.slider.getValue()+1;i<=view.slider.getMaximum();i++){
synchronized (lock) {
view.slider.setValue(i);
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
view.slider.setEnabled(true);
}).start();
}
private synchronized void sliderChangeHandler(int value) {
new Thread(() -> {
try {
synchronized (lock) {
Thread.sleep(1234);//some long calculations
view.tf.setText(String.valueOf(value));
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
public void setView(View v) {
view = v;
v.button.addActionListener(l -> buttonHandler());
v.slider.addChangeListener(l -> {
JSlider slider = (JSlider) l.getSource();
if (!slider.getValueIsAdjusting())
sliderChangeHandler(slider.getValue());
});
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Controller c = new Controller();
View v = new View();
c.setView(v);
JFrame f = new JFrame();
f.add(v.panel);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
});
}
}