У меня есть сочетание клавиш в моем приложении Java Swing, чтобы сохранить некоторые входные данные на сервер и перейти к следующему экрану, если пользователь нажимает Alt + V. Действие привязано к кнопке JButton, которую можно щелкнуть, чтобы сохранить/продолжить.
Я обнаружил, что при удерживании Alt+V действие запускалось несколько раз, а не только один раз, используя следующий код:
proceedBttn.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.ALT_DOWN_MASK), "proceedBtn");
Моя мысль состояла в том, чтобы исправить следующее, что вместо этого запускает действие только при отпускании сочетания клавиш:
proceedBttn().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.ALT_DOWN_MASK, true), "proceedBtn");
Однако приведенный выше код срабатывает только в том случае, если пользователь все еще держит Alt, когда отпускает V. Когда пользователь быстро набирает Alt+V, обычно он отпускает Alt до V (или одновременно), что приводит к тому, что действие вообще не срабатывает.
Есть ли хороший собственный вариант Java для решения этой проблемы, а не какая-то потенциально сложная логика защелки для каждого ярлыка в моем приложении?
Абсолютно! Мы не привязаны к каким-то конкретным ограничениям для этой задачи. Я ценю это.
Хорошо, сейчас напишу
@davidalayachew: и я собираюсь сказать вам прямо сейчас, что KeyListener не является способом решения этой проблемы, поскольку он будет работать только в том случае, если прослушиваемый компонент имеет и поддерживает фокус клавиатуры. ОП уже начал использовать привязки клавиш, что является правильным путем, зачем предлагать решение, которое заставляет их двигаться назад?
Нет, вы НЕ должны использовать KeyListener. Swing был разработан для использования с привязками клавиш. он запускал действие несколько раз, а не только один раз - у вас будет такая же проблема с KeyListener. Есть ли хороший собственный вариант Java для решения этой проблемы? Если у вас есть кнопка «Продолжить», почему бы не установить мнемонику для кнопки, чтобы использовать «Alt p». Затем буква «p» на кнопке будет подчеркнута, чтобы дать пользователю визуальную подсказку, как вызвать кнопку с помощью клавиатуры. Ознакомьтесь с учебным пособием по Swing Как использовать действия в качестве примера.
Похоже, многие люди не согласны, поэтому я оставлю это в покое.
@HovercraftFullOfEels, чтобы ответить на ваши вопросы, KeyListener очень удобен для меня, когда мне нужно просто проанализировать и обработать базовое поведение нажатия клавиш. У меня никогда не возникало проблем с фокусировкой, с которыми нельзя было бы легко справиться. Возможно, природа проекта OP делает его далеко не идеальным, но я использовал их с большим эффектом.
@camickr Я не имел в виду, что один только KeyListener решит проблему. Очевидно, что требуется больше усилий, чем это требуется. Я предложил KeyListener, потому что уже несколько раз решал одну и ту же проблему, и KeyListener был важной частью решения.
@davidalayachew, потому что я несколько раз решал одну и ту же проблему раньше - проблемы нет, поэтому решите, если вы используете правильный API. Использование действий и привязок клавиш — это более новое решение, используемое всеми компонентами Swing. Я предлагаю вам также прочитать учебник, на который я ссылаюсь, чтобы вы могли лучше понять преимущества этого подхода.
@camickr Я прекрасно понимаю преимущества этого подхода, я и раньше использовал привязки несколько раз. И когда я говорю о проблеме, я пытаюсь сказать «достичь определенной функциональности». Я не говорю, что привязки клавиш в чем-то проблематичны или что они каким-то образом неспособны решить эту проблему. Я упомянул KeyListener, потому что это вполне работоспособное решение, которое легко объяснить и которое отвечает основным потребностям. Когда я писал свой первый комментарий, я очень хорошо осознавал тот факт, что того же можно добиться с помощью привязки клавиш.
@GrahamMeehan, поскольку все категорически против использования KeyListener, вместо этого я напишу решение, в котором используются привязки клавиш.
@davidalayachew Не было причин предлагать использовать KeyListener, поскольку Key Bindings является предпочтительным решением Swing. Мы пытаемся ответить на вопрос с помощью текущих подходов к проектированию Swing. У вас не было причин предлагать KeyListener, чтобы запутать проблему (или продолжать останавливаться на этом), я уже дал решение в своем первом комментарии. Вы еще не читали учебник? Swing создаст для вас привязки клавиш.
@camickr - ваш первый комментарий ссылается только на широкий учебник и упоминает об изменении буквы, которую я использую для ярлыка, что не является чем-то, что у меня есть гибкость из-за наложенных на меня бизнес-требований.
@camickr «Мы пытаемся ответить на вопросы с помощью текущих подходов к проектированию Swing». Если это причина, по которой я не должен был предлагать KeyListener в первую очередь, то я принимаю эту причину. И когда я говорю, что набираю решение, я не говорю, что ваша ссылка не обеспечивает той функциональности, к которой они стремятся. Я говорю, что полностью закодированный пример, аналогичный тому, что пытается сделать OP, вероятно, будет полезен как им, так и всем остальным, кто увидит этот пост, поэтому я сделаю это. На самом деле, я также собираюсь связать учебник, который вы указали в моем ответе.
Ответ опубликован.
@GrahamMeehan ... и упоминает об изменении буквы, которую я использую для ярлыка, - было предложено использовать мнемонику. Логичный выбор состоит в том, чтобы сделать то, что делает стандартный пользовательский интерфейс, выбрав мнемонику, которая соответствует тексту кнопки. Однако это не является обязательным требованием. Я думаю, вы не пробовали. Все, что вам нужно было сделать, это скопировать демонстрационный код и изменить один символ для одной из мнемоник, чтобы посмотреть, будет ли работать «Alt-V». Нам не нужно объяснять код в учебнике. Если вам что-то непонятно в уроке, задайте вопрос. Мы не можем догадаться, что может вас смутить.
Вы должны использовать Мнемотехнику. Они не сталкиваются с проблемой, с которой вы столкнулись, потому что в Mnemonics удерживание Alt + V — это то же самое, что и удерживание кнопки компьютерной мышью. Кнопка остается нажатой до тех пор, пока вы не отпустите V, независимо от того, отпустили ли вы Alt до или после V.
Это решает проблему многократного нажатия, но обратите внимание, что это означает, что ввод происходит только тогда, когда вы отпускаете кнопку, а не когда вы нажимаете ее. Я думаю, что я решаю вашу актуальную проблему здесь (звучит как проблема XY), но обратите внимание, что событие кнопки произойдет не при нажатии, а при отпускании.
Итак, вы пытаетесь сделать так, чтобы ваша кнопка срабатывала только один раз при нажатии клавиши. Если это ваша цель, мы можем легко достичь этого с помощью Mnemonics и javax.swing.Action . Следуя предложению @camickr выше, я также рекомендую вам ознакомиться с руководством «Как использовать действия», предоставленным самими Oracle. Их учебные пособия по Swing превосходны.
Итак, для начала Swing предоставляет разработчикам возможность прикреплять Мнемонику ко многим ключевым компонентам Swing. Мнемоники — это функция специальных возможностей, которая позволяет пользователю выполнять более сложные действия с помощью комбинаций клавиш. В Swing это обычно делается через Alt+SomeKey. Мнемоники можно активировать, прикрепив Action
к компоненту, который вы хотите сделать легко доступным.
Согласно диаграмме компонентов Swing, поддерживаемых действием , все кнопки подтипа JComponent имеют возможность использовать мнемоники (ОБРАТИТЕ ВНИМАНИЕ, что не все компоненты Swing могут использовать мнемоники). У каждого из них есть метод под названием setAction(Action action)
. Определение метода для него: AbstractButton::setAction . А так как JButton является дочерним элементом AbstractButton
, значит, у JButton
тоже есть этот метод.
Итак, мы знаем, как добиться желаемого (используя Action
на JButton
), и мы знаем, что это возможно для кнопок (согласно приведенной выше схеме). Давайте построим Action
.
Чтобы кнопка срабатывала с помощью Action
, мы должны сначала создать Action
, установить мнемонику для действия, а затем прикрепить его к кнопке через JButton::setAction
. Вот быстрая и грязная демонстрация, которая показывает это.
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.AbstractAction;
import javax.swing.Action;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class Example1
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
JButton button = new JButton();
Action action =
new AbstractAction()
{
public void actionPerformed(ActionEvent event)
{
System.out.println("You pressed Alt-V");
}
};
action.putValue(Action.NAME, "This is the button text -- press Alt-V");
action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_V);
button.setAction(action);
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
}
}
Как вы можете видеть, если вы запустите вышеприведенное, он создаст маленькую JFrame
, не содержащую ничего, кроме кнопки. Если вы нажмете Alt-V, когда окно находится в фокусе, вы можете активировать нажатия кнопок. И, по умолчанию, комбинация клавиш не упирается ни в одну из выбоин, в которые вас завели InputMap и ActionMap.
Код в основном не требует пояснений, но наиболее важными являются 4 строки: 2 строки Action::putValue, строка AbstractButton::setAction
и строка внутри метода actionPerformed(ActionEvent event)
.
Метод actionPerformed(ActionEvent event)
— это то, что происходит всякий раз, когда нажимается кнопка. Строки Action::putValue
определяют действие. Первый указывает текст, который должен отображаться на JButton
. Второй прикрепляет комбинацию клавиш к самой Action
. Затем мы присоединяем этот Action
к JButton
, используя метод setAction(Action action)
. Как только это будет сделано, JButton
можно активировать с помощью Alt-V
.
Вот более сложный пример, показывающий, как это может выглядеть при вложении внутри нескольких экземпляров JPanel
.
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class KeyboardControls
{
public static void main(String[] args)
{
new KeyboardControls();
}
public KeyboardControls()
{
final JFrame frame = makeBasicJFrame();
final JPanel parentPanel = makeParentPanel();
frame.add(parentPanel);
frame.setVisible(true);
}
private JFrame makeBasicJFrame()
{
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setLocationByPlatform(true);
frame.setTitle("Keyboard Controls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return frame;
}
private JPanel makeParentPanel()
{
final JPanel parentPanel = new JPanel();
parentPanel.setLayout(new BorderLayout());
final CardLayout cardLayout = new CardLayout();
final JPanel cardLayoutPanel = makeCardLayoutPanel(cardLayout);
final Action nextAction =
new AbstractAction()
{
public void actionPerformed(final ActionEvent event)
{
cardLayout.next(cardLayoutPanel);
}
};
final JButton nextButton = makeNextButton(nextAction);
parentPanel.add(cardLayoutPanel, BorderLayout.CENTER);
parentPanel.add(nextButton, BorderLayout.SOUTH);
return parentPanel;
}
private void addPageToGivenPanel(final JPanel givenPanel, final String pageName)
{
final JPanel pagePanel = new JPanel();
final JLabel pageLabel = new JLabel();
pageLabel.setText(pageName);
pagePanel.add(pageLabel);
givenPanel.add(pagePanel, pageName);
}
private JPanel makeCardLayoutPanel(final CardLayout cardLayout)
{
final JPanel cardLayoutPanel = new JPanel();
cardLayoutPanel.setLayout(cardLayout);
addPageToGivenPanel(cardLayoutPanel, "PAGE_1");
addPageToGivenPanel(cardLayoutPanel, "PAGE_2");
addPageToGivenPanel(cardLayoutPanel, "PAGE_3");
addPageToGivenPanel(cardLayoutPanel, "PAGE_4");
addPageToGivenPanel(cardLayoutPanel, "PAGE_5");
return cardLayoutPanel;
}
private JButton makeNextButton(final Action nextAction)
{
final JButton nextButton = new JButton();
nextButton.setAction(nextAction);
final String buttonText = "NEXT -- Press Alt-V on your keyboard";
nextAction.putValue(Action.NAME, buttonText);
nextAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_V);
return nextButton;
}
}
Если вам сойдет с рук использование
KeyListener
, он сделает именно это за вас. Дайте мне знать, если это жизнеспособное решение для вас, и тогда я могу напечатать ответ.