为什么我的JFrame不会隐藏?

时间:2009-03-29 17:48:46

标签: java multithreading jframe show-hide netbeans6.1

我正在为我的高级设计项目在Netbeans 6.1中创建一个GUI,但我遇到了一个烦人的问题。像我的登录PopUp和其他临时Windows一样,当我告诉它时不会消失。我一直在研究如何解决这个问题大约2个月。我甚至为我的Pop Up疯了一个单独的线程,但它仍然无法正常工作....如果我真的不乱用任何其他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)
            {
            }
        }
    });

请帮助我!!!

5 个答案:

答案 0 :(得分:1)

Swing组件只能由swing事件派发线程操纵。

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

答案 1 :(得分:1)

经验法则:

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

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

稍微摆脱问题,你实际上要做的是什么?如果你只想要一个登录对话框来等待用户输入用户名和密码,那么一个不使用模态JDialog的原因(毕竟,这就是它的用途......)。

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

P.S。实际上有一些GUI操作方法可以安全地从其他线程调用,例如“只是设置标签”的电话通常是安全的。但哪些电话是安全的并不是非常明确,所以最好只是在实践中避免这个问题。

答案 2 :(得分:0)

很难诊断您的问题。我不确定您尝试使用wait方法做什么,但我建议单独留下wait / notify

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

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

}

因为我在你的代码中没有看到任何证据,我建议你read up on using event listeners而不是试图“等待”代码完成。

目前还不完全清楚你想要实现的目标,但你可能会更好地使用模态对话框:

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

}

答案 3 :(得分: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);
        }
    };
}

答案 4 :(得分: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
       }
    }
}