【问题标题】:Why wont my JFrame hide?为什么我的 JFrame 不隐藏?
【发布时间】:2009-03-29 17:48:46
【问题描述】:

我正在为我的高级设计项目在 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)
            {
            }
        }
    });

请帮帮我!!!

【问题讨论】:

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


    【解决方案1】:

    经验法则:

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

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

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

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

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

    【讨论】:

    • 我猜你们是对的......我想要的只是显示的窗口,用户从列表中选择他的名字,输入他的密码,一旦密码被确认,我希望窗户消失。我现在将框架更改为对话框以测试我的运气
    • 如果它不是文档线程安全的,它不是。事实上,JDK7 删除了一些说明方法是线程安全的文档,因为它们不是(也不能)。
    【解决方案2】:

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

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

    【讨论】:

    • 我不明白答案,请重新阅读我添加的内容,因为我认为我使用 SwingUtilities 对...
    • 你的代码看起来很奇怪。我建议你回去阅读 sun Swing 教程并从头开始。
    • 并不是我不欣赏其他 cmets,我知道如何编程 d00d,寻找解决方案,而不是从 9 月以来一直在进行的项目从头开始。我也使用 NetBeans,所以应该已经设置了任何令人讨厌、奇怪的 Swing 设置......
    • 这将是解决方案,因为他们会解释如何打开框架/对话框。所有的等待/睡觉看起来都相当狡猾。您是否尝试过为这些“临时”窗口使用 JDialog 而不是 JFrame?
    • 如果你让事件派发线程休眠,它将无法派发诸如点击按钮之类的事件,所以应用程序就像你所经历的那样冻结。
    【解决方案3】:

    很难诊断您的问题。我不确定你想用 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);
      }
    
    }
    

    【讨论】:

      【解决方案4】:

      干脆干脆怎么样:

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

      【讨论】:

        【解决方案5】:

        您真正想要使用的是模态 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
               }
            }
        }
        

        【讨论】:

        • 我已更改为对话框,并且没有更多可见性问题...非常感谢大家的所有输入。从来没有真正看到jFrame和jDialog之间的区别,所以我随意地使用了框架。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-29
        • 1970-01-01
        • 2017-03-21
        相关资源
        最近更新 更多