2 回答

TA贡献1831条经验 获得超10个赞
所以,答案是——这很复杂。它涵盖了广泛的主题,例如并发(一般)、GUI 开发、特定 API (Swing) 的最佳实践
该示例提供了两种执行“循环”的doInBackground方法(在CalculateWorker类的方法中提供)。
您可以按住JButton或按住 [kbd]Space[kbd] 栏,两者都会导致“主循环”运行,更新JTextArea结果...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
private CalculateWorker worker;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(20, 20);
ta.setEditable(false);
add(new JScrollPane(ta));
worker = new CalculateWorker(ta);
JButton btn = new JButton("Press");
btn.getModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
System.out.println("...isRunning = " + worker.isRunning());
if (!worker.isRunning()) {
return;
}
System.out.println("...isPressed = " + btn.getModel().isPressed());
System.out.println("...isPaused = " + worker.isPaused());
if (btn.getModel().isPressed()) {
worker.pause(false);
} else {
worker.pause(true);
}
}
});
add(btn, BorderLayout.SOUTH);
worker.execute();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "Space.released");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "Space.pressed");
am.put("Space.released", new CalculateAction(false, worker));
am.put("Space.pressed", new CalculateAction(true, worker));
}
public class CalculateWorker extends SwingWorker<List<String>, String> {
private AtomicBoolean run = new AtomicBoolean(true);
private AtomicBoolean paused = new AtomicBoolean(false);
private ReentrantLock pausedLocked = new ReentrantLock();
private Condition pausedCondition = pausedLocked.newCondition();
private JTextArea ta;
public CalculateWorker(JTextArea ta) {
this.ta = ta;
pause(true);
}
public void stop() {
run.set(false);
pausedLocked.lock();
pausedCondition.signalAll();
pausedLocked.unlock();
}
public void pause(boolean pause) {
paused.set(pause);
pausedLocked.lock();
pausedCondition.signalAll();
pausedLocked.unlock();
}
public boolean isPaused() {
return paused.get();
}
public boolean isRunning() {
return run.get();
}
@Override
protected List<String> doInBackground() throws Exception {
List<String> values = new ArrayList<>(256);
long value = 0;
System.out.println("!! Start running");
while (run.get()) {
while (paused.get()) {
System.out.println("!! I'm paused");
pausedLocked.lock();
try {
pausedCondition.await();
} finally {
pausedLocked.unlock();
}
}
System.out.println("!! Start loop");
while (!paused.get() && run.get()) {
value++;
values.add(Long.toString(value));
publish(Long.toString(value));
Thread.sleep(5);
}
System.out.println("!! Main loop over");
}
System.out.println("!! Run is over");
return values;
}
@Override
protected void process(List<String> chunks) {
for (String value : chunks) {
ta.append(value);
ta.append("\n");
}
ta.setCaretPosition(ta.getText().length());
}
}
public class CalculateAction extends AbstractAction {
private boolean start;
private CalculateWorker worker;
public CalculateAction(boolean start, CalculateWorker worker) {
putValue(NAME, "Calculate");
this.start = start;
this.worker = worker;
}
@Override
public void actionPerformed(ActionEvent e) {
worker.pause(start);
}
}
}
}
有没有更简单的解决方案?
当然,我总是先找最难、最难理解的解决方案(讽刺)
虽然“可能”降低复杂性是可能的,但该示例提供了许多“最佳实践”概念,您可以很好地学习和理解这些概念。
该解决方案也可以根据所使用的 API 以不同方式完成,因此,它是特定 API 选择的“最简单”解决方案。
我想从控制台做到这一点!
Java 不能这样做 - 它的控制台支持充其量只是基本的,并且不支持“按键按下/释放”操作的概念(因为它在单个线程中运行,否则它不可能这样做)。
您可能会尝试“有”解决方案,但它们需要链接到本机二进制文件的第三方库才能实现,这(可能)会减少它运行的平台数量
添加回答
举报