Кнопка обновления JavaSwing на основе флага сетевого подключения

У меня есть пользовательский интерфейс 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);
        }
    }
}

}

... он не перезапускает метод для обновления логического флага. Но почему? Это произошло бы только в том случае, если бы он работал в цикле в выделенном потоке.

g00se 07.10.2022 00:30

Я бы посмотрел на использование SwingWorker для опроса состояния соединения, если состояние изменится, то вы могли бы publish состояние и пользовательский интерфейс могли бы подобрать его и внести необходимые изменения.

MadProgrammer 07.10.2022 01:01

Мне было бы интересно увидеть реализацию этого. Я попытался сделать один на днях и обнаружил, что это на удивление нетривиально, в конечном итоге с исчерпанным и заблокированным пулом потоков. Признаюсь, что отказался от него заранее;)

g00se 07.10.2022 01:15

@ g00se Я смог это сделать. Пожалуйста, отправьте мой ответ ниже. Оказался проще, чем я ожидал.

Joe 07.10.2022 01:50

Таймер Swing может подойти.

Abra 07.10.2022 06:30

@ Абра не совсем. Основная рабочая нагрузка не будет происходить в EDT. SwingWorker больше подходит

g00se 07.10.2022 10:29
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мне удалось решить, используя следующий метод в 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, или вы можете использовать пару методов публикации/обработки.

Hovercraft Full Of Eels 07.10.2022 02:10

Вся цель использования SwingWorker состоит в том, чтобы избежать такого кода.

Hovercraft Full Of Eels 07.10.2022 02:10

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

MadProgrammer 07.10.2022 04:08
Ответ принят как подходящий

Опять же, этот код:

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

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