Java程序不是调用方法
Java Program is not Calling Method
public void startScanning() {
// Check if there is a webcam available
if (cameraView.getWebcamPanel() == null) {
return;
}
// Make sure the webcam is not null
if (cameraView.getWebcam() == null) {
return;
}
if (!cameraView.getWebcam().isOpen()) {
cameraView.getWebcam().open();
}
// Make sure the webcam is open
if (cameraView.getWebcam().isOpen()) {
// Create a SwingWorker thread to run in the background
worker = new SwingWorker<Void, Void>() {
try {
qrResult = new MultiFormatReader().decode(bitmap);
//System.out.println("qrResults: " + qrResult);
try {
// new error handling
int length = qrResult.getText().length();
if(length != 23){
JOptionPane.showMessageDialog(null, "Username and password is correct");
startScanning();
}
// end of error handling
我省略了一些语法,但由于某些原因,startScanning() 方法并没有在最后调用。显示对话框,但未调用该方法。有人可以解释为什么吗?
我想,这与 JOptionPane.showMessageDialog
有关。在程序继续之前,MesageDialog 必须关闭。如果您没有显示对话框的图形设备,它也会抛出 HeadlessException
。
检查任何打开的 windows 并对你的 try
块实施良好的 catch
。
一个小示例程序来展示正在发生的事情:
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Message");
System.out.println("done");
}
控制台输出 done
只会出现,如果你有图形设备,并且只有在你关闭对话框后 window。
一些观察:
- 同样,根据我的意见,根据所提供的信息,无法确定您的程序出了什么问题。考虑讲述和展示更多内容,尤其是 minimal example program.
- 我确实看到您没有正确遵守 Swing 线程规则。例如,您肯定会从 Swing 事件线程调用 JOptionPane,这是您永远不应该做的事情。您还递归地调用方法
startScanning()
,第一次是在 Swing 事件线程上,所有其他递归时间都在线程之外,这有点麻烦。我会找出它所属的位置并在该线程环境(在 EDT 上或关闭 EDT)中调用它,并且仅在该线程环境中调用它。
- 我自己,我会让我的 SwingWorker 告诉我它是否适当地完成了,同样这可以通过给 doInBackground return 一个值来轻松完成,或者你可以设置一个界限 属性 你的工人 class。
- 我非常喜欢将 PropertyChangeListeners 与我的 SwingWorker 一起使用,因为这可以更好地遵守 Demeter 法则——保持尽可能低的耦合。
例如
import java.awt.Component;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
@SuppressWarnings("serial")
public class FooGui extends JPanel {
// create my button's Action
private StartScanningAction action = new StartScanningAction("Start Scanning", this);
private JButton button = new JButton(action); // pass Action into button's constructor
// this is spinner is used just to show passing information into the SwingWorker
private JSpinner spinner = new JSpinner(new SpinnerNumberModel(25, 0, 50, 1));
// JTextField to show results from SwingWorker
private JTextField resultField = new JTextField(5);
public FooGui() {
resultField.setFocusable(false);
add(spinner);
add(button);
add(resultField);
}
// override method so that the JPanel controls whether its components are enabled or not
@Override
public void setEnabled(boolean enabled) {
button.setEnabled(enabled);
spinner.setEnabled(enabled);
super.setEnabled(enabled);
}
// get value so you can pass it into the Swingworker
public int getSpinnerValue() {
return (Integer) spinner.getValue();
}
// allow outside classes to set the resultField JTextField
public void setResultText(String text) {
resultField.setText(text);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("FooGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new FooGui());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
// Start our GUI in a Swing Thread-safe way
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
// JButton's Action
@SuppressWarnings("serial")
class StartScanningAction extends AbstractAction {
public static final int MINIMAL_VALUE = 50;
private FooGui fooGui; // the main GUI
private Component sourceComp; // the JButton
private int initValue; // value from the spinner
private JDialog dialog; // modal dialog to hold our JProgressBar
public StartScanningAction(String name, FooGui fooGui) {
super(name);
this.fooGui = fooGui;
}
@Override
public void actionPerformed(ActionEvent e) {
this.sourceComp = (Component) e.getSource();
// get the top-level window that holds our JButton
Window win = SwingUtilities.getWindowAncestor(sourceComp);
// create our JDialog in a lazy way
if (dialog == null) {
// JProgressBar to show in dialog when worker is working
JProgressBar progBar = new JProgressBar();
// if we plan to set the worker's progress property, then the dialog would not be indeterminate
progBar.setIndeterminate(true);
// pass win into dialog. Make it modal
dialog = new JDialog(win, "Awaiting Worker", ModalityType.APPLICATION_MODAL);
dialog.add(progBar);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
// disable the main GUI
fooGui.setEnabled(false);
// extract info from the main GUI
initValue = fooGui.getSpinnerValue();
// call the method that gets our worker going
startScanning(initValue);
}
// method that gets worker going. This is called on the EDT
private void startScanning(int initValue) {
// create a worker object
StartScanningWorker worker = new StartScanningWorker(initValue);
// add property change listener to the worker
worker.addPropertyChangeListener(new PcListener());
// execute the worker
worker.execute();
// show our dialog. this freezes program flow so must be done last
dialog.setVisible(true);
}
// listen for state changes to the worker. This is done on the EDT
private class PcListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is done working
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
dialog.dispose(); // get rid of the modal dialog
// extract worker
StartScanningWorker worker = (StartScanningWorker) evt.getSource();
try {
// deal with any exceptions that occurred during worker's run
worker.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
return; // this one's a bad exception
}
// get worker's value and check if it is adequate
int someValue = worker.getSomeValue();
if (someValue < MINIMAL_VALUE) {
// our worker failed -- display a JOptionPane. We're on the EDT so this thread is OK for this
String message = String.format("someValue is %d which is less than the "
+ "minimal value, %d. To re-run worker", someValue, MINIMAL_VALUE);
String title = "Some Value Not High Enough";
int messageType = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(sourceComp, message, title, messageType);
// recursive call made on the EDT. Be careful doing this.
startScanning(initValue);
} else {
// else the worker's result was good. Display the results and re-enable the GUI
fooGui.setResultText(String.valueOf(someValue));
fooGui.setEnabled(true);
}
}
}
}
}
// worker that doesn't do anything important
class StartScanningWorker extends SwingWorker<Void, Void> {
private static final long SLEEP_TIME = 2 * 1000;
public static final String SOME_VALUE = "some value";
private int someValue;
public StartScanningWorker(int someInitialValue) {
// initialize the worker with a value from the GUI
this.someValue = someInitialValue;
}
public int getSomeValue() {
return someValue;
}
// if I want someValue to be a bound property. Not necessary in this example
public void setSomeValue(int someValue) {
int oldValue = this.someValue;
this.someValue = someValue;
firePropertyChange(SOME_VALUE, oldValue, someValue);
}
@Override
protected Void doInBackground() throws Exception {
// simulate along-running process
Thread.sleep(SLEEP_TIME);
// get a random value
int value = (int) (100 * Math.random()) + someValue;
setSomeValue(value);
// end the worker
return null;
}
}
public void startScanning() {
// Check if there is a webcam available
if (cameraView.getWebcamPanel() == null) {
return;
}
// Make sure the webcam is not null
if (cameraView.getWebcam() == null) {
return;
}
if (!cameraView.getWebcam().isOpen()) {
cameraView.getWebcam().open();
}
// Make sure the webcam is open
if (cameraView.getWebcam().isOpen()) {
// Create a SwingWorker thread to run in the background
worker = new SwingWorker<Void, Void>() {
try {
qrResult = new MultiFormatReader().decode(bitmap);
//System.out.println("qrResults: " + qrResult);
try {
// new error handling
int length = qrResult.getText().length();
if(length != 23){
JOptionPane.showMessageDialog(null, "Username and password is correct");
startScanning();
}
// end of error handling
我省略了一些语法,但由于某些原因,startScanning() 方法并没有在最后调用。显示对话框,但未调用该方法。有人可以解释为什么吗?
我想,这与 JOptionPane.showMessageDialog
有关。在程序继续之前,MesageDialog 必须关闭。如果您没有显示对话框的图形设备,它也会抛出 HeadlessException
。
检查任何打开的 windows 并对你的 try
块实施良好的 catch
。
一个小示例程序来展示正在发生的事情:
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, "Message");
System.out.println("done");
}
控制台输出 done
只会出现,如果你有图形设备,并且只有在你关闭对话框后 window。
一些观察:
- 同样,根据我的意见,根据所提供的信息,无法确定您的程序出了什么问题。考虑讲述和展示更多内容,尤其是 minimal example program.
- 我确实看到您没有正确遵守 Swing 线程规则。例如,您肯定会从 Swing 事件线程调用 JOptionPane,这是您永远不应该做的事情。您还递归地调用方法
startScanning()
,第一次是在 Swing 事件线程上,所有其他递归时间都在线程之外,这有点麻烦。我会找出它所属的位置并在该线程环境(在 EDT 上或关闭 EDT)中调用它,并且仅在该线程环境中调用它。 - 我自己,我会让我的 SwingWorker 告诉我它是否适当地完成了,同样这可以通过给 doInBackground return 一个值来轻松完成,或者你可以设置一个界限 属性 你的工人 class。
- 我非常喜欢将 PropertyChangeListeners 与我的 SwingWorker 一起使用,因为这可以更好地遵守 Demeter 法则——保持尽可能低的耦合。
例如
import java.awt.Component;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
@SuppressWarnings("serial")
public class FooGui extends JPanel {
// create my button's Action
private StartScanningAction action = new StartScanningAction("Start Scanning", this);
private JButton button = new JButton(action); // pass Action into button's constructor
// this is spinner is used just to show passing information into the SwingWorker
private JSpinner spinner = new JSpinner(new SpinnerNumberModel(25, 0, 50, 1));
// JTextField to show results from SwingWorker
private JTextField resultField = new JTextField(5);
public FooGui() {
resultField.setFocusable(false);
add(spinner);
add(button);
add(resultField);
}
// override method so that the JPanel controls whether its components are enabled or not
@Override
public void setEnabled(boolean enabled) {
button.setEnabled(enabled);
spinner.setEnabled(enabled);
super.setEnabled(enabled);
}
// get value so you can pass it into the Swingworker
public int getSpinnerValue() {
return (Integer) spinner.getValue();
}
// allow outside classes to set the resultField JTextField
public void setResultText(String text) {
resultField.setText(text);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("FooGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new FooGui());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
// Start our GUI in a Swing Thread-safe way
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
// JButton's Action
@SuppressWarnings("serial")
class StartScanningAction extends AbstractAction {
public static final int MINIMAL_VALUE = 50;
private FooGui fooGui; // the main GUI
private Component sourceComp; // the JButton
private int initValue; // value from the spinner
private JDialog dialog; // modal dialog to hold our JProgressBar
public StartScanningAction(String name, FooGui fooGui) {
super(name);
this.fooGui = fooGui;
}
@Override
public void actionPerformed(ActionEvent e) {
this.sourceComp = (Component) e.getSource();
// get the top-level window that holds our JButton
Window win = SwingUtilities.getWindowAncestor(sourceComp);
// create our JDialog in a lazy way
if (dialog == null) {
// JProgressBar to show in dialog when worker is working
JProgressBar progBar = new JProgressBar();
// if we plan to set the worker's progress property, then the dialog would not be indeterminate
progBar.setIndeterminate(true);
// pass win into dialog. Make it modal
dialog = new JDialog(win, "Awaiting Worker", ModalityType.APPLICATION_MODAL);
dialog.add(progBar);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
// disable the main GUI
fooGui.setEnabled(false);
// extract info from the main GUI
initValue = fooGui.getSpinnerValue();
// call the method that gets our worker going
startScanning(initValue);
}
// method that gets worker going. This is called on the EDT
private void startScanning(int initValue) {
// create a worker object
StartScanningWorker worker = new StartScanningWorker(initValue);
// add property change listener to the worker
worker.addPropertyChangeListener(new PcListener());
// execute the worker
worker.execute();
// show our dialog. this freezes program flow so must be done last
dialog.setVisible(true);
}
// listen for state changes to the worker. This is done on the EDT
private class PcListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is done working
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
dialog.dispose(); // get rid of the modal dialog
// extract worker
StartScanningWorker worker = (StartScanningWorker) evt.getSource();
try {
// deal with any exceptions that occurred during worker's run
worker.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
return; // this one's a bad exception
}
// get worker's value and check if it is adequate
int someValue = worker.getSomeValue();
if (someValue < MINIMAL_VALUE) {
// our worker failed -- display a JOptionPane. We're on the EDT so this thread is OK for this
String message = String.format("someValue is %d which is less than the "
+ "minimal value, %d. To re-run worker", someValue, MINIMAL_VALUE);
String title = "Some Value Not High Enough";
int messageType = JOptionPane.ERROR_MESSAGE;
JOptionPane.showMessageDialog(sourceComp, message, title, messageType);
// recursive call made on the EDT. Be careful doing this.
startScanning(initValue);
} else {
// else the worker's result was good. Display the results and re-enable the GUI
fooGui.setResultText(String.valueOf(someValue));
fooGui.setEnabled(true);
}
}
}
}
}
// worker that doesn't do anything important
class StartScanningWorker extends SwingWorker<Void, Void> {
private static final long SLEEP_TIME = 2 * 1000;
public static final String SOME_VALUE = "some value";
private int someValue;
public StartScanningWorker(int someInitialValue) {
// initialize the worker with a value from the GUI
this.someValue = someInitialValue;
}
public int getSomeValue() {
return someValue;
}
// if I want someValue to be a bound property. Not necessary in this example
public void setSomeValue(int someValue) {
int oldValue = this.someValue;
this.someValue = someValue;
firePropertyChange(SOME_VALUE, oldValue, someValue);
}
@Override
protected Void doInBackground() throws Exception {
// simulate along-running process
Thread.sleep(SLEEP_TIME);
// get a random value
int value = (int) (100 * Math.random()) + someValue;
setSomeValue(value);
// end the worker
return null;
}
}