Удалить Jframe после использования
Для входа в программу создаю Login, который наследует Jframe.
public class Login extends JFrame {
private int window_w = 200, window_h = 100;
private static JTextField loginField;
private static JTextField passField;
public void frame() {
После успешной проверки введенных данных выполняю метод, в котором пытаюсь этот Jframe удалить, он мне больше не понадобиться. Метод этого же класса, но видимо я не так обращаюсь к Jframe и ни одна из этих команд мне не помогла. Как правильно это можно сделать?
this.getContentPane().setVisible(false);
this.dispose();
getContentPane().dispose();
Полный код приложения
public class Login extends JFrame {
private int window_w = 200, window_h = 100;
private static JTextField loginField;
private static JTextField passField;
public void frame() {
setUndecorated(true);
setSize(window_w, window_h);
getContentPane().setLayout(null);
loginField = new HintText("Логин");
loginField.setBounds(52, 10, 100, 20);
getContentPane().add(loginField);
loginField.setEditable(true);
loginField.setHorizontalAlignment(SwingConstants.CENTER);
loginField.setFont(new Font("Times New Roman", Font.BOLD, 15));
passField = new HintText("Пароль");
passField.setBounds(52, 40, 100, 20);
getContentPane().add(passField);
passField.setEditable(true);
passField.setHorizontalAlignment(SwingConstants.CENTER);
passField.setFont(new Font("Times New Roman", Font.BOLD, 15));
setLocationRelativeTo(null);
setVisible(true);
JButton btnLog = new JButton("ВХОД");
btnLog.setBounds(52, 70, 100, 20);
btnLog.addActionListener(new ActionListenerLogin());
getContentPane().add(btnLog);
}
class ActionListenerLogin implements ActionListener {
public void actionPerformed(ActionEvent e) {
Connection con = new Connection();
String pass = passField.getText();
String login = loginField.getText();
con.checkLogin(pass, login);
}
}
public void runGui(String guiType) {
// this.getContentPane().setVisible(false);
// this.dispose();
// getContentPane().dispose();
// System.out.println(guiType);
if (guiType.contains("")) {
Main.Run();
}
}
}
Вызов runGui
public void checkLogin(String pass, String login) {
java.sql.Connection connection = null;
Login lg = new Login();
try {
connection = cpds.getConnection();
PreparedStatement stCL = connection.prepareStatement("select * FROM users WHERE login = ? AND password = ?");
stCL.setString(1, login);
stCL.setString(2, pass);
ResultSet rsCL = stCL.executeQuery();
while (rsCL.next()) {
guiType = rsCL.getString("guiType");
}
lg.runGui(guiType);
} catch (Exception e) {
System.out.println("Error: " + e);
}finally { try {if(connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}
}
Ответы (1 шт):
Закрытие окна
Для того, чтобы закрыть окно можно отправить событие закрытия окна(WindowEvent.WINDOW_CLOSING).
Таким образом Вы запустите сценарий закрытия окна, со всеми вытекающими из этого последствиями.
С его помощью можно закрыть окно программным способом при возникновении определенных условий, во время событий, или при отработке дополнительных элементов управления.
При этом эффект будет абсолютно таким же, как при нажатии на кнопку закрытия окна(X).
this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
В данном случае предполагается что переменная this хранит в себе ссылку на экземпляр формы Login, которую необходимо закрыть.
Замечание:
Не стоит забывать что в данном случае отработают все слушатели(
Listeners) настроенные на закрытие окна.Соответственно, если Вы установили:
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)то Ваше приложение после этого прекратит своё выполнение.
по умолчаниюdefaultCloseOperationимеет значениеJFrame.HIDE_ON_CLOSE
Альтернативный способ
Если Вам нужно закрыть окно без обработки слушателей закрытия, Вы можете воспользоваться методом JFrame::dispose(), вызванном на экземпляре окна.
frame.dispose();
Анализ приложенного кода
У меня есть ряд замечаний по приложенному Вами коду.
Статические переменные
private static JTextField loginField;
private static JTextField passField;
Я советую воздержаться от использования статических переменных в случаях, когда данные объекты явно принадлежат одному из экземпляров того же класса.
Это очень плохая практика, которая может и немного облегчает доступ к некоторым объектам, но при этом и содержит большое количество подводных камней и является потенциальным источником множества ошибок за счёт смешения контекстов класса и одного из экземпляров.
Я мог бы понять это, если бы Вы хотели получить доступ к данным полям в другом классе(события). Но вложенный класс имеет доступ к родительским полям и в нем можно без каких-либо проблем получить доступ к переменным loginField и passField. Поэтому применение статических переменных в данном случае для меня вообще непонятно.
Каждый раз когда Вас посещает мысль об использовании статической переменной, подумайте дважды или трижды: А можете ли Вы добиться того же результата за счет правильной композиции?
Мы однозначно отказываемся от их использования в данном случае:
private JTextField loginField;
private JTextField passField;
Обработка события
Часто приходится работать с обработкой событий и желательно уметь извлекать все необходимые объекты непосредственно из объекта события(Потому что далеко не всегда имеется возможность использования вложенного класса).
Вы всегда можете получить доступ к кнопке, по которой был произведен клик, следующим образом:
// берем объект события(e)
// обращаемся к источнику события (наша кнопка)
// приводим её к типу (JButton), потому что метод возвращает Component
JButton button = (JButton)e.getSource();
После того, как у нас появляется доступ к кнопке, мы можем получить и доступ ко всей форме, получив их с помощью метода getParent()
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
Login loginForm = (Login) button
.getParent() // JPanel
.getParent() // JLayeredPane
.getParent() // JRootPane
.getParent() // Login
;
// ...
// после этого можем получить данные из формы...
String pass = loginForm.passField.getText();
String login = loginForm.loginField.getText();
// ...
}
Для удобства, кстати, можно сделать методы получения логина и пароля в классе формы Login
public class Login extends JFrame {
// ...
public String getLogin(){
return loginField.getText();
}
public String getPassword(){
return passField.getText();
}
// ...
}
После этого код выглядит еще лучше, да и переноситься будет без каких либо проблем:
String pass = loginForm.getPassword();
String login = loginForm.getLogin();
Кстати для всего вышеописанного необязательно было создавать класс ActionListenerLogin можно было бы просто сделать так:
btnLog.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//обработка события...
}
});
Ну а если Вы хотите оправдать создание данного класса, то Вы можете добавить в него свойства, в котором будут храниться ссылка на форму или/и на поля.
Таким образом, код также может стать более стабильным и он будет без проблем переносить изменения в компановке формы и Вы сможете избежать не самого приятного извлечения объекта формы из объекта события.
Сначала прокидываем объект формы в слушатель при создании
btnLog.addActionListener(new ActionListenerLogin(this));
И в обработчике:
class ActionListenerLogin implements ActionListener {
Login loginForm;
public ActionListenerLogin(Login loginForm) {
this.loginForm = loginForm;
}
public void actionPerformed(ActionEvent e) {
// ...
// И здесь можно сразу начинать работать с формой
String pass = loginForm.getPassword();
String login = loginForm.getLogin();
// ...
}
}
Это может помочь, когда у Вас достаточно сложная обработка события.
Вы можете вынести его из класса формы и использовать.
Точка закрытия формы
А вот здесь у Вас начинается настоящий детектив в коде, основными действующими лицами которого являются методы runGui() и checkLogin()
Посмотрите внимательнее:
- метод
runGui()вызывается в методеcheckLogin() - внутри которого создается форма
- которая содержит метод
runGui() - и которая содержит в себе обработку события
- внутри которого вызывается метод
checkLogin() - внутри которого вызывается метод
runGui()... - ...
- ... и так можно продолжать бесконечно
Вы не находите это подозрительным?
- Зачем в этом методе создается форма?
- И зачем в при обработке клика по форме вызывать метод, который будет создавать еще одну такую же форму?
Кстати говоря, когда я писал блок про статические переменные я не стал упоминать о том, что Вы можете создать еще один объект формы авторизации в рамках того же, приложения. Но Вы это сделали. Таким образом при создании новой формы перезаписываются значения статических переменныхloginFieldиpassField, что приведет к ошибке. Что опять же говорит не в пользу использования статических переменных. - зачем Вам форма в методе, который делает запрос к базе данных?
- зачем запускать какое-то еще GUI рядом с работой с БД
Здесь Вы нарушаете достаточно важный принцип: Single-Responsibility Principle, SRP он же принцип единственной ответственности.
Другими словами "этот метод слишком много на себя берёт"!
данный метод должен:
- либо проверять наличие пользователя с таким логином и паролем и возвращать
trueилиfalse - либо возвращать пользователя с таким логином и паролем
- либо запускать GUI для уже проверенного и полученного пользователя
но никак не все вместе.
Именно из-за того, что данный метод делает так много всего получается такая путаница, когда Вы вроде пытаетесь проверить наличие такого пользователя, при этом тут же создаете еще одну форму.
Как лучше поступить виднее только Вам, но в рамках данного ответа я предлагаю, вместо данного метода создать метод, который ищет и возвращает пользователя по логину и паролю.
Для того чтобы вернуть пользователя, нужно создать класс User:
public class User {
private String login;
// ... остальные поля
private String guiType;
// геттеры и сеттеры
public String getLogin() { return login; }
public void setLogin(String login) { this.login = login; }
public String getGuiType() { return guiType; }
public void setGuiType(String guiType) { this.guiType = guiType; }
// и т.д. для остальных полей
}
В методе же, мы проверяем наличие результатов.
И при наличии: создаем объект пользователя, заполняем его и возвращаем.
public User findUserByLoginAndPassword(String login, String pass) throws UserNotFoundException {
java.sql.Connection connection = null;
try {
connection = cpds.getConnection();
PreparedStatement stCL = connection.prepareStatement("select * FROM users WHERE login = ? AND password = ?");
stCL.setString(1, login);
stCL.setString(2, pass);
ResultSet rsCL = stCL.executeQuery();
if (rsCL.next()) {
// Если есть результаты - создаем пользователя
// устанавливаем все необходимые поля
User user = new User();
user.setLogin(rsCL.getString("login"));
user.setGuiType(rsCL.getString("guiType"));
// ... и остальные поля тоже
return user;
// и возвращаем его
}
} catch (Exception e) {
System.out.println("Error: " + e);
} finally { try {if(connection != null) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}
// В ПРОТИВНОМ СЛУЧАЕ ВЫКИДЫВАЕМ ИСКЛЮЧЕНИЕ !!!
throw new UserNotFoundException("Пользователь с таким логином и паролем не найден!");
}
Как Вы могли заметить, когда мы не находим пользователя - мы выбрасываем исключение UserNotFoundException
Для того, чтобы выбросить такое исключение, нам нужно его сначала создать.
Достаточно просто наследоваться от Exception:
public class UserNotFoundException extends Exception {
public UserNotFoundException(String message) {
super(message);
}
}
После этого нам необходимо:
- вызвать данный метод при обработке события клика
- обработать исключение
- получить пользователя
- закрыть окно
- запустить GUI
class ActionListenerLogin implements ActionListener {
Login loginForm;
public ActionListenerLogin(Login loginForm) {
this.loginForm = loginForm;
}
public void actionPerformed(ActionEvent e) {
Connection con = new Connection();
String pass = loginForm.getPassword();
String login = loginForm.getLogin();
try{
// в моём методе другой порядок параметров
User user = con.findUserByLoginAndPassword(login, pass);
// закрываем окно авторизации
loginForm.dispatchEvent(new WindowEvent(loginForm, WindowEvent.WINDOW_CLOSING));
// также здесь можно воспользоваться и альтернативным методом
// loginForm.dispose();
// он будет тут работать
// и запускаем GUI c нужным типом
loginForm.runGui(user.getGuiType());
}catch (UserNotFoundException e){
e.printStackTrace();
}
}
}
Единственное что осталось сделать Вам - это создать форму Login