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;
   }
}