0

我正在为我的高级设计项目在 Netbeans 6.1 中创建一个 GUI,但我遇到了一个烦人的障碍。当我告诉它时,像我的登录弹出窗口和其他临时窗口不会消失。我一直在研究如何解决这个问题大约 2 个月。我什至为我的弹出窗口创建了一个单独的线程,但它仍然无法工作......如果我真的不与任何其他 GUI 组件混淆,它会消失的唯一方法......我的示例代码应该有助于描述我的愤怒...不要介意影子代码,这是出于测试目的,这显然没有帮助。

//This method is called once a user presses the "first" login button on the main GUI
public synchronized void loginPopUpThread() {
    doHelloWorld = new Thread(){
        @Override
        public synchronized void run()
        {
            try
            {
                    loginPopUpFrame.pack();
                    loginPopUpFrame.setVisible(true);
                    System.out.println("waitin");
                    doHelloWorld.wait();
                    System.out.println("Not Sleepin..");
                    loginPopUpFrame.pack();
                    loginPopUpFrame.setVisible(false);
            }
            catch (InterruptedException e)
            {
            }
        }
    };
    doHelloWorld.start();

//This is called when the "second" loginB is pressed and the password is correct...
public synchronized void notifyPopUp() {
    synchronized(doHelloWorld) {

        doHelloWorld.notifyAll();
        System.out.println("Notified");
    }
}

我也尝试过 Swing Utilities,但也许我实施错了,因为这是我第一次使用它们。它基本上与上面的代码做同样的事情,除了窗口在等待时冻结,上面的代码没有做:

javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public synchronized void run() {
            try
            {
                    loginPopUpFrame.pack();
                    loginPopUpFrame.setVisible(true);
                    System.out.println("waitin");
                    wait();
                        System.out.println("Not Sleepin.");
                        loginPopUpFrame.pack();
                       loginPopUpFrame.setVisible(false);
            }
            catch (InterruptedException e)
            {
            }
        }
    });

请帮我!!!

4

5 回答 5

1

Swing 组件只能由 swing 事件调度线程操作。

SwingUtilites 类具有向调度线程提交任务的方法。

于 2009-03-29T17:57:44.400 回答
1

经验法则:

  • 不要在任意线程中操作 GUI 组件;总是安排在事件线程中操作它们
  • 永远不要在事件线程内等待或休眠 (因此,永远不要在发送到 invokeLater() 的代码内)

所以你如何解决这个问题的答案是“其他方式”......

稍微退后一步,您实际上想要做什么?如果您只想让登录对话框等待用户输入用户名和密码,是否有理由不只使用模态 JDialog(毕竟,这就是它的用途......)。

如果您确实希望某个任意线程等待关闭窗口/操作 GUI 的信号,那么您需要在另一个线程中等待,然后使用实际的 GUI 操作使线程调用 SwingUtilities.invokeLater()代码。

PS 实际上有一些 GUI 操作方法可以安全地从其他线程调用,例如“只是设置标签”的调用通常是安全的。但是哪些调用是安全的并没有很好的定义,所以最好在实践中避免这个问题。

于 2009-03-29T19:58:27.153 回答
0

很难诊断您的问题。我不确定你想用等待方法做什么,但我建议单独留下等待/通知。

此代码有两个框架 - 当您创建第二个框架时,第一个将隐藏,直到您关闭它。

public class SwapFrames {

  private JFrame frame;

  private JFrame createMainFrame() {
    JButton openOtherFrameButton = new JButton(
        "Show other frame");

    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container contentPane = frame.getContentPane();
    contentPane.setLayout(new FlowLayout());
    contentPane.add(openOtherFrameButton);
    frame.pack();

    openOtherFrameButton
        .addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            onClickOpenOtherFrame();
          }
        });

    return frame;
  }

  private void onClickOpenOtherFrame() {
    frame.setVisible(false);

    JFrame otherFrame = new JFrame();
    otherFrame
        .setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    otherFrame.setContentPane(new JLabel(
        "Close this to make other frame reappear."));
    otherFrame.pack();
    otherFrame.setVisible(true);
    otherFrame.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosed(WindowEvent e) {
        frame.setVisible(true);
      }
    });
  }

  public static void main(String[] args) {
    JFrame frame = new SwapFrames().createMainFrame();
    frame.setVisible(true);
  }

}

因为我在您的代码中没有看到任何证据,所以我建议您阅读使用事件侦听器而不是试图“等待”代码完成。

尚不完全清楚您要实现的目标,但使用模态对话框可能会更好:

public class DialogDemo {

  public JFrame createApplicationFrame() {
    JButton openDialogButton = new JButton("Open Dialog");

    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container container = frame.getContentPane();
    container.setLayout(new FlowLayout());
    container.add(openDialogButton);
    frame.pack();

    openDialogButton
        .addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            onOpenDialog(frame);
          }
        });

    return frame;
  }

  private void onOpenDialog(JFrame frame) {
    JDialog dialog = createDialog(frame);
    dialog.setVisible(true);
  }

  private JDialog createDialog(JFrame parent) {
    JButton closeDialogButton = new JButton("Close");

    boolean modal = true;
    final JDialog dialog = new JDialog(parent, modal);
    dialog
        .setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    Container container = dialog.getContentPane();
    container.add(closeDialogButton);
    dialog.pack();
    dialog.setLocationRelativeTo(parent);

    closeDialogButton
        .addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            dialog.setVisible(false);
          }
        });

    return dialog;
  }

  public static void main(String[] args) {
    new DialogDemo().createApplicationFrame().setVisible(
        true);
  }

}
于 2009-03-29T19:57:31.787 回答
0

如何简单地做:

//This method is called once a user presses the "first" login button on the main GUI
public void loginPopUpThread() {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            loginPopUpFrame.pack();
            loginPopUpFrame.setVisible(true);
        }
    };
}

//This is called when the "second" loginB is pressed and the password is correct...
public void notifyPopUp() {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            loginPopUpFrame.setVisible(false);
        }
    };
}
于 2009-03-29T21:47:49.683 回答
0

您真正想要使用的是模态 JDialog。

请注意,其中的一些内容被忽略了。这是你的作业/项目。

public void actionPerformed(ActionEvent e)
{
   // User clicked the login button
   SwingUtilities.invokeLater(new Runnable()
   {
       public void run()
       {
         LoginDialog ld = new LoginDialog();
         // Will block
         ld.setVisible(true);
       }
   });
}

public class LoginDialog extends JDialog
{
    public LoginDialog()
    {
        super((Frame)null, "Login Dialog", true);

        // create buttons/labels/components, add listeners, etc
    }

    public void actionPerformed(ActionEvent e)
    {
       // user probably clicked login
       // valid their info
       if(validUser)
       {
          // This will release the modality of the JDialog and free up the rest of the app
          setVisible(false);
          dispose();
       }
       else
       {
          // bad user ! scold them angrily, a frowny face will do
       }
    }
}
于 2009-03-29T22:29:07.510 回答