Почему мой JFrame скрыть?

Я нахожусь в процессе создания графического интерфейса в Netbeans 6.1 для моего старшего дизайн-проекта, но я столкнулся с досадной загадкой. Временные окна, такие как мой логин PopUp и другие, не исчезнут, когда я скажу это. Я изучал, как решить эту проблему в течение приблизительно 2 месяцев. Я даже разозлил отдельный поток для моего всплывающего окна, но он все равно не будет работать... единственный способ, которым он исчезнет, ​​если я буквально не буду связываться с любым из других компонентов графического интерфейса.... мой пример кода должен помочь описать мой гнев... не возражаю против теневого кода, это было для целей тестирования, что, очевидно, не помогло.

//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 ответов

Решение

Эмпирические правила:

  • Не манипулируйте компонентами GUI в произвольных потоках; всегда устраивай манипулировать ими в ветке событий
  • Никогда не ждите и не спите в потоке событий (поэтому никогда не внутри кода, отправляемого invokeLater())

Таким образом, ответ на то, как вы решаете эту проблему, "каким-то другим способом"...

Немного отступив от проблемы, что вы на самом деле пытаетесь сделать? Если вы просто хотите, чтобы диалог входа в систему ожидал, когда пользователь введет имя пользователя и пароль, есть ли причина не просто использовать модальный JDialog (в конце концов, для этого он и нужен...).

Если вы действительно хотите, чтобы какой-то произвольный поток ожидал сигнала, чтобы закрыть окно / манипулировал GUI, тогда вам нужно сделать ожидание в другом потоке, а затем заставить этот поток вызвать SwingUtilities.invokeLater() с фактической манипуляцией с GUI. код.

PS На самом деле есть некоторые методы манипуляции с графическим интерфейсом, которые безопасно вызывать из других потоков, например, вызовы, которые "просто устанавливают метку", часто безопасны. Но какие звонки безопасны, не очень четко определены, поэтому лучше просто избежать этой проблемы на практике.

Компоненты Swing должны обрабатываться только потоком диспетчеризации событий колебания.

Класс SwingUtilites имеет методы для отправки задач в поток диспетчеризации.

Как насчет просто:

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

То, что вы действительно хотите использовать, это модальный 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
       }
    }
}

Трудно диагностировать вашу проблему. Я не уверен, что вы пытаетесь сделать с методами ожидания, но я рекомендую оставить в ожидании/ уведомить в одиночку.

Этот код имеет два фрейма - при создании второго фрейма первый скрыт, пока вы его не закроете.

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

}
Другие вопросы по тегам