Как заставить кнопку в JavaFX ничего не делать?
Имеется кнопка, которая обрабатывает более-менее весомое по времени событие. В моем случае, она в JavaFX приложении при нажатии каждый раз отображает новую капчу. К кнопке привязан метод типа onAction из контроллера, в нем все это происходит. Я хочу, чтобы если я нажимал на кнопку один раз, а потом сразу же второй, то пока метод после первого нажатия еще не завершит свою работу, второй метод не вызывался. Допустим, в самом конце метода я вывожу в консоль слово «конец», и нужно, чтобы я мог нажимать на кнопку сколько угодно раз, пока не увижу это слово, и чтобы при этом ничего не происходило. Я пробовал по классике поставить флаг, типа в начале метода сделать
if (buttonIsPressed) return;
И после него buttonIsPressed = true а в конце всего buttonIsPressed = false
Но это не помогло. Я так понимаю, что эти методы имеют свойство как бы накапливаться, может добавляются в очередь, а потом исполняются один за другим, и вот сколько раз я нажму на кнопку, столько раз метод потом будет срабатывать. Если я нажимал на кнопку 10 раз за пару секунд, то по после того, как я закончил клацать, картинка капчи еще раз 5 поменялась, и продолжалось это длиться тоже где-то пару секунд, короче нежелательно, чтобы такое происходило. Я пишу приложение для себя, в целях изучения, то есть можно и так оставить, но душа хочет чтобы было идеально
Какие тут могут быть методы решения? Я подумал, что может быть нужно как-то создавать второй поток, и тогда все будет выполняться одновременно, параллельно, а не последовательно, а может просто поставить какую-то задержку, таймер на кнопку между нажатиями, но не знаю как это все реализовать. А может быть в JavaFX уже есть готовый какой-нибудь объект, метод, который мне поможет, и не нужно ничего придумывать? Не знаю
- Вопрос задан более года назад
- 356 просмотров
10 комментариев
Средний 10 комментариев
Не понятный вопрос.
Алексей @MicroKlizma Автор вопроса
Nurik,
Допустим, при нажатии на кнопку вызывается метод:
public void action() throws InterruptedException
После вывода текста в консоль, я жму на кнопку 5 раз, до того как тред засыпает на 5 секунд (имитация длительного выполнения кода). После того, как он просыпается, все мои 5 нажатий все равно обрабатываются. Я накликал по кнопке в тот момент, когда выполнялся метод, и после него будут выполняться остальные методы, то есть еще 5 раз выведется слово action в консоль, хотя тред в момент кликов, казалось бы, ничего не обрабатывал
Как сделать так, чтобы пока выполняется код (в данном случае, пока выполняется Thread.sleep), я нажимал на кнопку сколько угодно раз, и после того, как код первого нажатия, первого метода закончил выполняться (тред проснулся), у меня не выполнялись новые методы action() и не выводился текст?

Алексей, переменную устанавливайте в true false и проверяйте чтобы делать и не делать

Орхан Гасанлы @azerphoenix Куратор тега Java
А вы пробовали просто отключать кнопку (деактивировать, сделать некликабельной) ее, пока выполняется некая операция?
https://stackoverflow.com/questions/17871329/disab.
А когда операция завершится включите кнопку.
Алексей @MicroKlizma Автор вопроса
сергей кузьмин, я написал что это не помогает

используйте runLater и все в руках
https://docs.oracle.com/javase/8/javafx/api/javafx.
Алексей @MicroKlizma Автор вопроса
Орхан Гасанлы, мне предлагали это решение в ответах, я попробовал и в комментах написал что это не сработало, в итоге ответ удалили. Ни флаг ни setDisable у меня не работают.
После button.setDisable(true) я вывожу в консоль button.isDisable и выводится true. Затем тред засыпает, я в это время спамлю кнопку и она все равно нажимается, после того как тред просыпается все эти true выводятся
Алексей @MicroKlizma Автор вопроса
сергей кузьмин, я попробовал это
Сначала я сделал без runLater. Нажатие на кнопку вызывает метод action внутри контроллера:
public void action() throws InterruptedException < MyThread mt = new MyThread(); Thread thread = new Thread(mt); thread.start(); >class MyThread implements Runnable < @Override public void run() < buttonClicked(); >>
И все прекрасно работает. Я добился того, чего нужно. В buttonClicked в начале и конце я меняю button.setDisable на true и false соответственно. И когда я делаю клики, кнопка не реагирует на них, пока buttonClicked() не завершит работу
Но проблема в том, что после первого нажатия у меня только один раз выскакивает
Exception in thread «Thread-3» java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
Естественно исключение это плохо, от него нужно избавляться, для этого как раз в гугле говорят использовать Platform.runLater(). Таким образом, я переделал метод run()
@Override public void run() < Platform.runLater( () ->buttonClicked() ) ; >
После него исключения не возникает, но код не работает так, как работал без runLater. Я снова могу нажимать на кнопку сколько угодно раз и нажатия будут как бы накапливаться, пока все методы, которые нажатие вызвало, не выполнятся

Алексей, здорово спс за апдейт
треды содайте для выполения каждого в своем
и решайте сложные задачи

Алексей, кстати создайте проект посмотреть на гитхбе — у меня был один вялотекущий я бы мульт кнопку туда вброил на будущее
Решения вопроса 1
Алексей @MicroKlizma Автор вопроса
Благодаря комментам под вопросом и некоторому гуглению разобрался что к чему. Я решил проблему путем создания нового потока. Таким образом, поток будет работать параллельно с основным потоком. И в то время пока кнопка существует, параллельно и независимо другой поток может ей управлять. При нажатии на кнопку я вызываю метод onAction(), в котором создаю новый поток с точкой входа в виде метода, который все должен обрабатывать
public void onAction() throws InterruptedException
Далее делаем в этом методе все, что хотели делать, но при этом, пока выполняется код, делаем кнопку неактивной: button.setDisable(true). Благодаря этому она меняет цвет и пропадает возможность по ней кликать (также вроде можно модифицировать ее стиль в этом состоянии в css файле: .button:disabled)
public void someMethod() < button.setDisable(true); //code button.setDisable(false); >
Это решение у меня работало нормально и так, как я хотел. Но оно вызывает исключение, хотя на него можно забить если обернуть в try catch, все равно будет работать:
Exception in thread «Thread-3» java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
Я считаю, что хороший программист должен с исключениями бороться 🙂
Как я понял, исключение выбрасывается тогда, когда меняется вид (UI), элементы (узлы) (node) приложения. Видимо, это можно делать только в FX applicaton thread. В моей программе я изменял текстовое поле и поле с изображением. И решение есть — делать все эти изменения с помощью Platform.runLater(). В него, так же как и при создании Thread, передается объект типа Runnable. Runnable — это функциональный интерфейс, поэтому вместо того, чтобы создавать целый класс, реализующий Runnable, для краткой записи воспользуемся лямбда-выражениями. В моем случае для моего приложения метод будет выглядеть примерно так:
public void someMethod() < button.setDisable(true); //some code Platform.runLater( () ->textField.setText(text) ); //some code Platform.runLater( () -> imageView.setImage(image) ); //some code button.setDisable(false); >
Интересно, что setDisable() по идее тоже нужно оборачивать в Platform.runLater(). Но я протестировал, программа срабатывала без исключений даже если не обернуть, хотя казалось бы, этот метод заставляет кнопку менять цвет и делает ее неактивной, некликабельной, меняет состояние кнопки (кстати узнать это состояние можно с помощью isDisabled()), но нет, все работает
Как сделать кнопку в java
Предположим, я хочу создать кнопку с меткой, как показано ниже:
«Имя» должно быть во второй строке.
Я пытался написать:
new JButton(«Ваше \\n Имя»)
К сожалению, у меня ничего не получилось. У вас есть какие-нибудь советы?
Короткий ответ: вы не сможете это сделать без значительных усилий. JButton не содержит внутренних возможностей для переноса длинных строк или начала новой строки, если текст содержит \n.
Все компоненты JFC отображаются с помощью соответствующего ComponentUI. Вместо того, чтобы помещать весь код отрисовки в метод paint JButton, JButton передает фунции отображения в ButtonUI (расширение ComponentUI). ComponentUI позволяет нам менять look and feel для Java Swing GUI на лету просто меняя рендереры ComponentUI в нашем JComponents.
Одна из реализаций ButtonUI, которую может использовать JButton — это BasicButtonUI. Если вы достаточно храбры для того, чтобы заглянуть в код BasicButtonUI, вы обнаружите метод:
protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text)
paintText() выполняет всю грязную работу по отрисовке строки. Если мы копнем немного глубже, то обнаружим, что этот метод передает само отображение в метод drawString() в BasicGraphicsUtils:
public static void drawString(Graphics g,String text,int underlinedChar,int x,int y)
drawString() выполняет небольшую обработку и далее просто вызывает метод drawString() из класса Graphics. Нам пришлось повозиться, но теперь достаточно очевидно, почему JButton не будет делать перенос строки.
- Вы можете создать свою собственную JButton, расширив JButton и перекрыв метод paint. В этом методе вы разобъете строку на основе \n, сделаете несколько вычислений размеров, отрисуете кнопку и затем выведете разбитый текст. Однако, если вы пойдете этим путем, ваша кнопка потеряет возможность подключать look and feel. Также вы можете утратить некоторые эффекты отображения в Swing.
- Вы можете создать новый ButtonUI, который будет правильно форматировать ваш текст.
- Вы можете использовать комбинацию из JLabels и JButton для получения того, что вам надо, вместо своей собственной кнопки. Попробуйте следующее:
JButton b = new JButton(); b.setLayout(new BorderLayout()); JLabel label1 = new JLabel("Ваше"); JLabel label2 = new JLabel("Имя"); b.add(BorderLayout.NORTH,label1); b.add(BorderLayout.SOUTH,label2);
Если вы обнаружите, что вам приходится часто использовать многострочную кнопку, вы можете вложить вышеприведенное решение в новый класс, скажем MultiLineButton. Этот класс будет расширять JButton, содержать две копии JLabel и методы void setLabel1Text(String text) и void setLabel2Text(String text).
Swing могут отображать HTML!
Похоже, что мой превоначальный ответ о многострочных кнопках был неполным. Когда я писал свой ответ, я использовал Java 1.1.7 и Swing 1.0.3, для которых ответ остается правильным. Многие разработчики (включая меня) по-прежнему используют эти старые версии. Однако новые версии Swing способны отображать HTML.
-
Довольно много компонентов в Swing могут отрисовывать свое содержимое используя HTML. В результате, вы можете создать многострочную кнопку с помощью следующего кода:
JButton b = new JButton("Your
Name");
JButton myButton = new JButton ("HelloWorld");
Заметьте, что не все компоненты в Swing подерживают HTML.
Об авторе
Тони Синтес работает старшим консультантом в ObjectWave, специализируясь на телекоммуникациях. Тони работает с Java начиная с 1997 года и является Sun-certified Java 1.1 программистом и Java 2 разработчиком.
Reprinted with permission from the March 2000 edition of JavaWorld magazine.
Copyright © ITworld.com, Inc., an IDG Communications company.
View the original article at: http://www.javaworld.com/javaworld/ 2000-03/01-qa-button.html
- 22.11 — «Сбер» представил ИИ-художника Kandinsky 3.0 — он стал точнее и изучил отечественный культурный код
- 22.11 — Ubisoft отметила 20-летие Prince of Persia: The Sands of Time обнадёживающими новостями о проблемном ремейке
- 22.11 — «Джеймс Уэбб» нашёл самый большой зародыш галактических скоплений в ранней Вселенной
- 22.11 — NVIDIA представила сетевой ускоритель SuperNIC для гипермасштабируемых ИИ-нагрузок
- 22.11 — У «ВКонтакте» произошёл массовый сбой — пользователи не могут попасть в соцсеть
- 21.11 — Релиз FreeBSD 14.0
- 21.11 — Криптовалютная биржа Bittrex Global объявила о закрытии
- 21.11 — ИИ-помощник Copilot появился в предварительных версиях Windows 10
- 21.11 — Huawei сохранит поддержку Android-приложений для глобальных устройств даже после выхода HarmonyOS NEXT
- 21.11 — Акции Microsoft взлетели до максимума на фоне скандала вокруг OpenAI и найма Сэма Альтмана
- 21.11 — В WhatsApp теперь можно авторизоваться по электронной почте
- 21.11 — Накануне публикации квартального отчёта NVIDIA курс акций компании обновил исторический рекорд
- 17.11 — Apple добавит поддержку современного протокола для СМС в iOS в 2024 году — она давно есть у Android
- 17.11 — SpaceX заверила регулятора, что Starlink не создаст помех наземным сотовым сетям
- 17.11 — Суд оштрафовал издателя PUBG Mobile на 1 млн рублей за нарушение закона о локализации данных россиян
- 17.11 — Microsoft подтвердила скорое появление ИИ-помощника Copilot в Windows 10
- 17.11 — Alibaba потеряла $21 млрд стоимости из-за отказа от отделения облачного бизнеса
- 16.11 — Microsoft и Synopsys создали ИИ, который поможет разрабатывать процессоры
- 16.11 — «Яндекс Карты» будут показывать больше подробностей о городе
- 16.11 — В Швейцарии создали первый процессор на 2D-транзисторах, которому не нужна внешняя память
Установка кнопки по умолчанию для JFrame в Java

При нажатии на вышеуказанную кнопку на консоли отображается следующее:

Средняя оценка 0 / 5. Количество голосов: 0
Спасибо, помогите другим — напишите комментарий, добавьте информации к статье.
Или поделись статьей
Видим, что вы не нашли ответ на свой вопрос.
Помогите улучшить статью.
Напишите комментарий, что можно добавить к статье, какой информации не хватает.
Урок 9. Три cпособа обработки нажатия кнопки в мобильном приложении (Android Studio)
В этом уроке вы узнаете, как в андроид повесить слушатель (OnClickListener) на кнопку (Buttons). Как заставить кнопку реагировать на нажатие, и как обрабатывать нажатие кнопки на экране android устройства. Также вы познакомитесь с тремя разными способами обработки нажатия кнопки.
В первом случае на вход методу setOnClickListener подается объект с интерфейсом View.OnClickListener который и будет обрабатывать нажатия.
Во втором случае мы тоже используем метод setOnClickListener, но в качестве обработчика используем текущий объект Activity (this) реализующий интерфейс View.OnClickListener
И третий способ заключается он в использовании атрибута onClick для элемента Button в XML макете и создании своего метода в классе активности.
Исходный код проекта можно скачать по ссылке внизу
Исходный код проекта скачать
