以下是实际问题代码的编译程序副本
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Dummy {
public static boolean getUserCheck(int size, boolean Check) {
if (Check) {
int ret = JOptionPane.showConfirmDialog(null, size + " entries, Yes or no?",
"Warning", 0);
if (ret > 0) {
System.out.println("User said No: " + ret);
return false;
} else if (ret <= 0) {
System.out.println("user said Yes: " + ret);
return true;
}
}
return true;
}
public static void workerMethod1() {
System.out.println("am worker method 1");
}
public static void workerMethod2() {
System.out.println("am worker method 2");
}
public static void main(String[] args) {
System.out.println("mainthread code line 1");
int size = 13;
boolean thresholdBreach = true;
if (getUserCheck(size, thresholdBreach)) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
workerMethod1();
}
});
SwingUtilities.invokeLater(new Runnable() {
public void run() {
workerMethod2();
}
});
}
System.out.println("mainthread code line 2");
System.out.println("mainthread code line 3");
}
}
我希望在另一个线程上运行main()中的if{}
块。因为这2行,
System.out.println("mainthread code line 2");
System.out.println("mainthread code line 3");
无需等待if(){}
阻止
另一个问题是,专家建议在事件线程上运行确认对话框方法。
int ret = JOptionPane.showConfirmDialog(null, size + " entries, Yes or no?",
"Warning", 0);
请帮帮我!!!!
答案 0 :(得分:3)
JOptionPane是一个Swing方法,应该在EDT上调用, E vent D ispatch T hread,并且仅在此线程上,所以它表明上面的所有代码应该在EDT上,并且大多数SwingUtilities.invokeLater(new Runnable()
调用都是完全没必要的。唯一必要的将是主要的一个,您可以在其中启动Swing GUI代码,以及需要在后台线程中进行Swing调用的任何区域。同样,如果在后台线程中生成上述任何代码,则JOptionPane不应该在该线程中。
有关此答案或任何其他答案的更多具体信息,请在您的问题中提供更具体的信息。让我们结束所有困惑。让我们完全快速理解您的问题的最佳方法是,如果您要创建并发布minimal example program,这是一个小而完整的程序,只有必要的代码来证明您的问题,我们可以复制,粘贴,编译和运行而无需修改。
我有一种潜在的怀疑,即沿着MVC线路进行体面的重构可以解决你的大部分问题。你的代码是非常线性的,它的代码行必须相互跟随它的if块,而且它还与你的GUI紧密耦合,对我来说是两个红旗。也许更好的是线性代码更少,更多事件和状态驱动代码,后台代码通过观察者通知与GUI交互的代码,以及后台代码同样响应GUI中控件通知的状态更改。
您的控件需要两个SwingWorkers,一个用于获取行数,另一个用于获取其余数据(如果用户决定这样做)。我将PropertyChangeListener添加到第一个SwingWorker,以便在行计数数据准备就绪时收到通知,然后一旦将其提供给视图,供用户选择是否继续。如果他决定继续,我会调用第二个SwingWorker来获取数据的主体。
例如,我正在谈论的内容的粗略草图:
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
@SuppressWarnings("serial")
public class SwingWorkerFooView extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
private JProgressBar progressBar;
private JDialog dialog;
public SwingWorkerFooView() {
add(new JButton(new ButtonAction("Foo", this)));
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public boolean showOptionGetAllData(int numberOfRows) {
String message = "Number of rows = " + numberOfRows + ". Get all of the data?";
String title = "Get All Of Data?";
int optionType = JOptionPane.YES_NO_OPTION;
int result = JOptionPane.showConfirmDialog(this, message, title, optionType);
return result == JOptionPane.YES_OPTION;
}
public void showProgressBarDialog() {
progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
Window window = SwingUtilities.getWindowAncestor(this);
dialog = new JDialog(window, "Hang on", ModalityType.APPLICATION_MODAL);
JPanel panel = new JPanel();
panel.add(progressBar);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
}
public void closeProgressBarDialog() {
dialog.dispose();
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SwingWorkerFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SwingWorkerFooView());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class ButtonAction extends AbstractAction {
Workers workers = new Workers();
private SwingWorker<Integer, Void> firstWorker;
private SwingWorker<List<String>, Void> secondWorker;
private SwingWorkerFooView mainGui;
public ButtonAction(String name, SwingWorkerFooView mainGui) {
super(name);
this.mainGui = mainGui;
}
@Override
public void actionPerformed(ActionEvent e) {
firstWorker = workers.createFirstWorker();
firstWorker.addPropertyChangeListener(new FirstPropertyChangeListener());
firstWorker.execute();
mainGui.showProgressBarDialog();
}
private class FirstPropertyChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
mainGui.closeProgressBarDialog();
try {
int numberOfRows = firstWorker.get();
boolean getAllData = mainGui.showOptionGetAllData(numberOfRows);
if (getAllData) {
secondWorker = workers.createSecondWorker();
secondWorker.addPropertyChangeListener(new SecondPropertyChangeListener());
secondWorker.execute();
mainGui.showProgressBarDialog();
} else {
// user decided not to get all data
workers.cleanUp();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
private class SecondPropertyChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
mainGui.closeProgressBarDialog();
try {
List<String> finalData = secondWorker.get();
// display finalData in the GUI
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
class Workers {
// database object that may be shared by two SwingWorkers
private Object someDataBaseVariable;
private Random random = new Random(); // just for simulation purposes
private class FirstWorker extends SwingWorker<Integer, Void> {
@Override
protected Integer doInBackground() throws Exception {
// The Thread.sleep(...) is not going to be in final production code
// it's just to simulate a long running task
Thread.sleep(4000);
// here we create our database object and check how many rows there are
int rows = random.nextInt(10 + 10); // this is just for demonstration purposes only
// here we create any objects that must be shared by both SwingWorkers
// and they will be saved in a field of Workers
someDataBaseVariable = "Fubar";
return rows;
}
}
private class SecondWorker extends SwingWorker<List<String>, Void> {
@Override
protected List<String> doInBackground() throws Exception {
// The Thread.sleep(...) is not going to be in final production code
// it's just to simulate a long running task
Thread.sleep(4000);
List<String> myList = new ArrayList<>();
// here we go through the database filling the myList collection
return myList;
}
}
public SwingWorker<Integer, Void> createFirstWorker() {
return new FirstWorker();
}
public void cleanUp() {
// TODO clean up any resources and database stuff that will not be used.
}
public SwingWorker<List<String>, Void> createSecondWorker() {
return new SecondWorker();
}
}
所有这一切的关键是不要以线性控制台程序的方式思考,而是使用观察者设计模式,即某种类型的监听器来检查GUI和模型的状态变化。
它本质上是:
显示进度条对话框或以某种方式通知用户该工作人员正在执行。
当工作人员完成后,将通知监听器,然后您可以查询工作人员(此处通过get()
方法调用)查看其最终结果。
答案 1 :(得分:0)
是; SwingUtilities.invokeLater()只是将您的runnable放在AWT事件队列中以便稍后处理,并且可以随时安全地执行此操作。