【问题标题】:Java Modal Dialog Won't Block Code ExecutionJava 模态对话框不会阻止代码执行
【发布时间】:2014-06-29 02:52:23
【问题描述】:

基本上.. 我使用 swing 制作了一个 JDialog。现在我希望它向调用它的 JFrame 返回一个值。问题是,每当我调用 JDialog 的构造函数时,即使我设置了setModal(true),它也不会阻塞线程。我在这里遗漏了什么明显的东西吗?

private final JPanel contentPanel = new JPanel();
private File chosenFile = null;
private JList list;
private File[] files;

public File getInformation()
{
    return chosenFile;      
}

/**
 * Create the dialog.
 */
public PatientPicker(JFrame parent)
{
    super(parent);
    setModal(true);
    setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    setLocationRelativeTo(parent);

    setBounds(100, 100, 450, 396);
    getContentPane().setLayout(new BorderLayout());
    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
    getContentPane().add(contentPanel, BorderLayout.CENTER);

    files = new File(ClientInfo.GetAppData() + "/patients").listFiles(new TextFileFilter());

    {
        JPanel buttonPane = new JPanel();
        buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
        getContentPane().add(buttonPane, BorderLayout.SOUTH);
        {
            JButton okButton = new JButton("OK");
            okButton.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent arg0) {
                    if(files.length != 0)
                        chosenFile = files[list.getSelectedIndex()];
                    dispose();
                }
            });
            okButton.setActionCommand("OK");
            buttonPane.add(okButton);
            getRootPane().setDefaultButton(okButton);
        }
        {
            JButton cancelButton = new JButton("Cancel");
            cancelButton.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent arg0) {
                    dispose();
                }
            });
            cancelButton.setActionCommand("Cancel");
            buttonPane.add(cancelButton);
        }
    }
}

然后是我如何创建它:

PatientPicker patientPicker = new PatientPicker(frmReportGenerator);
File dataFile = patientPicker.getInformation();

【问题讨论】:

  • Modal 是关于阻止用户与其他组件的交互,而不是其他线程。
  • @chrylis 根据this,这不一定是真的......
  • 您提供的链接适用于在事件线程上运行的代码。所以是的,@chrylis 所说的所有 都是 必然是正确的。
  • 好的,所以我想我的问题是:如何获得我想要的行为?我只需要从 JDialog 中返回一个值

标签: java swing jdialog


【解决方案1】:

你说:

问题是,每当我调用 JDialog 的构造函数时,即使我设置了 setModal(true),它也不会阻塞线程。我在这里遗漏了什么明显的东西吗?

构造函数永远不会阻塞事件线程。模态意味着事件线程仅在您在模态对话框上调用 setVisible (true) 时才会被阻止(根据 api)。


不相关的问题:您不应该在 JButtons 上使用 MouseListeners,而应该在 ActionListeners 上使用。否则你现在会遇到大问题,比如当你通过空格键按下文件时,当它按下时,什么也没有发生,在以后的代码中,比如当你禁用按钮时,它仍然是功能正常,即使它看起来已禁用。


现在,如果您仍然遇到问题,那么您可能希望发布更多代码,minimal code example program,这将使我们能够理解和体验您的问题。


编辑
你说:

是的。用户在 JDialog 中选择了一个文件,我希望它返回到调用它的 JFrame。

为什么不直接使用 JFileChooser 模式对话框?


编辑 2
使用 JOptionPane 的示例:

import java.awt.event.*;

import javax.swing.*;

@SuppressWarnings("serial")
public class SwingFoo extends JPanel {
   private JTextField fileField = new JTextField(20);
   private JButton showDialog = new JButton(new ShowDialogAction("Show Dialog",
         KeyEvent.VK_D, this));

   public SwingFoo() {
      fileField.setEditable(false);
      fileField.setFocusable(false);
      add(new JLabel("File Selected:"));
      add(fileField);
      add(showDialog);
   }

   public void setFileFieldText(String text) {
      fileField.setText(text);
   }

   private static void createAndShowGui() {
      SwingFoo mainPanel = new SwingFoo();

      JFrame frame = new JFrame("SwingFoo");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class ShowDialogAction extends AbstractAction {
   private SwingFoo swingFoo;

   public ShowDialogAction(String name, int mnemonic, SwingFoo swingFoo) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.swingFoo = swingFoo;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      PatientPicker patientPicker = new PatientPicker();
      int result = JOptionPane.showConfirmDialog(swingFoo, patientPicker,
            "Select Something", JOptionPane.OK_CANCEL_OPTION);
      if (result == JOptionPane.OK_OPTION) {
         swingFoo.setFileFieldText(patientPicker.getSelectedItem());
      }
      patientPicker.setVisible(true);
   }
}

@SuppressWarnings("serial")
class PatientPicker extends JPanel {
   private static final String[] ITEMS = {"Sunday", "Monday", "Tuesday", "Wednesday",
         "Thursday", "Friday", "Sunday", "Fubar", "Snafu", "DILLIGAF", "BOHICA"};
   private JList<String> selectionList = new JList<>(ITEMS);

   public PatientPicker() {
      add(new JScrollPane(selectionList));
      selectionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
   }

   public String getSelectedItem() {
      return selectionList.getSelectedValue();
   }

}

【讨论】:

  • @JABFreeware: 构建一个对话框以在可见时阻止它。
  • @JABFreeware:如果构造函数受阻,您将无法构造对象、设置属性更改侦听器并使其可见。我不能抱怨它的设置方式。
  • 好吧..这一切都说得通。那么我将如何获得我正在寻找的行为呢?我要做的就是从我的 JDialog 返回一个值,我想我错误地在线实现了解决方案......
  • @CCInc:你到底想返回什么?一个文件?
  • @CCInc 使用 JFileChooser 的附件查看 this example。也许你会感兴趣。
【解决方案2】:

您需要做的是,一旦用户完成与对话框的交互,假设他们单击了确定按钮,就可以向主窗口发送通知。 您可以通过创建一个匿名类并将其传递到 Dialog 的构造函数中来做到这一点。

假设您在主窗口中使用名为 openDialogBtn 的按钮打开对话框:

openDialogBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            new PatientPicker(this, new FileSelectionNotifier() {
                public void okButtonPressed(File chosenFile) {

                    // do whatever you need to do with the file (assign to a member variable
                    // or call another thread to do some kind of processing

                }
            });

在你的对话窗口中,你需要有这样的东西:

okButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {


            dispose();
            // notify that the ok button was pressed
            fileSelectionNotifier.okButtonPressed(chosenFile); 
        }
}

【讨论】:

    猜你喜欢
    • 2016-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多