Вопрос

Я занимаюсь созданием графического пользовательского интерфейса в Netbeans 6.1 для своего старшего дизайнерского проекта, но столкнулся с досадной проблемой.Временные окна Windows, такие как всплывающее окно входа в систему и другие, не исчезнут, когда я об этом скажу.Я искал, как решить эту проблему, около 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)
            {
            }
        }
    });

ПОЖАЛУЙСТА, ПОМОГИТЕ МНЕ!!!

Это было полезно?

Решение

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

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

Итак, ответ на то, как решить эту проблему, — «каким-то другим способом»…

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

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

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

Другие советы

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

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

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

В этом коде есть два фрейма — когда вы создаете второй фрейм, первый скрывается, пока вы его не закроете.

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

}

Как насчет того, чтобы сделать просто:

//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
       }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top