У меня есть пользовательский интерфейс Java Swing, где мне нужно отключить кнопку в пользовательском интерфейсе, если я не могу обнаружить активное подключение к Интернету.
Пока код работает правильно, но когда я отключаюсь от Интернета, он не перезапускает метод для обновления логического флага.
Как я могу добавить событие к этому флагу, чтобы моя кнопка использовала его в течение всего времени существования приложения?
public class Main {
private static JButton button;
private static boolean testButtonEnabled;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
/*
* function that returns true/false if connected to the internet
*/
if (Utils.isConnectedToInternet()) {
logger.debug("System is connected to the internet");
testButtonEnabled=true;
} else {
logger.debug("System is not connected to the internet");
testButtonEnabled=false;
}
Main window = new Main();
window.frame.setVisible(true);
button = new JButton("my button");
/*
* set the internet status
*/
button.setVisible(testButtonEnabled);
}
}
}
}
Я бы посмотрел на использование SwingWorker для опроса состояния соединения, если состояние изменится, то вы могли бы publish состояние и пользовательский интерфейс могли бы подобрать его и внести необходимые изменения.
Мне было бы интересно увидеть реализацию этого. Я попытался сделать один на днях и обнаружил, что это на удивление нетривиально, в конечном итоге с исчерпанным и заблокированным пулом потоков. Признаюсь, что отказался от него заранее;)
@ g00se Я смог это сделать. Пожалуйста, отправьте мой ответ ниже. Оказался проще, чем я ожидал.
Таймер Swing может подойти.
@ Абра не совсем. Основная рабочая нагрузка не будет происходить в EDT. SwingWorker больше подходит




Мне удалось решить, используя следующий метод в initialize() фрейма.
Добавление этой части изменения в свингворкер позволило кнопке проверять флаг и назначать его себе всякий раз, когда он изменяется.
Теперь, когда Интернет отключен, кнопка отключена, а при подключении кнопка включена.
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
public Void doInBackground()
{
while(true)
{
try {
isConnectedToInternet = Utils.isConnectedToInternet();
if (isConnectedToInternet) {
btn_online2.setEnabled(isConnectedToInternet);
} else {
btn_online2.setEnabled(isConnectedToInternet);
}
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
Этот ответ не только неверен, он опасен. Вы никогда не должны делать вызов Swing, такой как btn_online2.setEnabled(isConnectedToInternet);, непосредственно из метода doInBackground или любого фонового потока. Это опасно, так как код может работать в 95% случаев, но затем неожиданно и неожиданным образом дать сбой. Вместо этого рассмотрите возможность использования прослушивателя изменений свойств и поддержки изменения свойств Swing, или вы можете использовать пару методов публикации/обработки.
Вся цель использования SwingWorker состоит в том, чтобы избежать такого кода.
Кроме того, не позволяйте работникам делать предположения о вашем пользовательском интерфейсе. Вместо этого рабочий процесс должен «публиковать» или возвращать состояние/информацию, которая затем потребляется создавшей ее сущностью.
Опять же, этот код:
SwingWorker<Void, String> worker = new SwingWorker<Void, String>()
{
public Void doInBackground()
{
while(true)
{
try {
isConnectedToInternet = Utils.isConnectedToInternet();
if (isConnectedToInternet) {
btn_online2.setEnabled(isConnectedToInternet);
} else {
btn_online2.setEnabled(isConnectedToInternet);
}
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
опасен, поскольку он вносит мутационные изменения в компонент Swing из фонового потока. Хотя этот код может работать в 95% случаев, он может дать сбой непредсказуемым образом и в непредсказуемое время. Лучше изменять компоненты Swing только в потоке событий. Например, даже это было бы лучше:
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
@Override
public Void doInBackground() {
while(true) {
try {
isConnectedToInternet = Utils.isConnectedToInternet();
// note that there is no need for the if/else block
SwingUtilities.invokeLater(() -> {
btn_online2.setEnabled(isConnectedToInternet);
});
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
worker.execute();
или еще лучше, используя публикацию/процесс SwingWorker:
SwingWorker<Void, Boolean> worker = new SwingWorker<Void, Boolean>() {
@Override
public Void doInBackground() {
while(true) {
try {
isConnectedToInternet = Utils.isConnectedToInternet();
// note that there is no need for the if/else block
publish(Utils.isConnectedToInternet());
logger.debug("Internet connection status: " + isConnectedToInternet);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
protected void process(List<Boolean> chunks) {
for (Boolean chunk : chunks) {
btn_online2.setEnabled(chunk);
}
}
};
worker.execute();
... он не перезапускает метод для обновления логического флага. Но почему? Это произошло бы только в том случае, если бы он работал в цикле в выделенном потоке.