Как я могу изменить ярлык / горячую клавишу “description” в элементе swing JMenu?

StackOverflow https://stackoverflow.com/questions/1684085

  •  18-09-2019
  •  | 
  •  

Вопрос

Наше приложение swing использует клавишу "пробел" в качестве сочетания клавиш.Другими словами, если вы нажмете пробел в любом месте окна приложения, оно выполнит определенное поведение.Более того, такое же поведение также может быть выполнено с помощью JMenuItem в строке меню окна.

Обычный способ реализовать это - просто установить "пробел" в качестве "ACCELERATOR_KEY" для соответствующего JMenuItem, и просто позволить swing позаботиться обо всем остальном.К сожалению, мы не можем этого сделать, потому что, если мы установим "пробел" в качестве клавиши ACCELERATOR_KEY, ярлык срабатывает каждый раз, когда пользователь нажимает пробел, даже в неподходящие моменты, например, когда пользователь вводит обычный текст в текстовое поле внутри окна приложения.

Чтобы обойти эту проблему, мы внедрили пробел как псевдоконную комбинацию клавиш БЕЗ надлежащей установки ее в соответствующем JMenuItem в качестве КЛАВИШИ УСКОРЕНИЯ.Это работает нормально, за исключением, конечно, в JMenuItem нет никакого сочетания клавиш "подсказка" на нем.То есть пункт меню должен содержать надпись "пробел" маленькими серыми буквами прямо на пункте меню, чтобы наши пользователи могли "обнаружить" сочетание клавиш, не читая руководство пользователя.

Но текст отсутствует, поскольку он добавляется в пункт меню только при установке сочетания клавиш в качестве КЛАВИШИ АКСЕЛЕРАТОРА.

Итак, мой вопрос заключается в следующем: Как я могу изменить текст подсказки по сочетанию клавиш в нашем JMenuItem, чтобы я мог сам добавить соответствующую "подсказку"?Было бы неплохо, если бы я мог сделать это без необходимости возиться с внешним видом, поскольку наше приложение является мультиплатформенным и использует несколько разных LAFS.

Это было полезно?

Решение

Спасибо за предложения, ребята.Это обсуждение привело меня к паре различных решений, которые работают.

Во-первых, чтобы решить проблему отображения текста ярлыка "подсказка" без фактического наличия работающего сочетания клавиш.Просто добавьте комбинацию клавиш в Action / JMenuItem как обычно (это даст вам текст подсказки), а затем просто отключите комбинацию клавиш сразу после ее добавления.Простой (но не единственный) способ сделать это - создать подкласс JMenuItem и переопределить один метод:

   @Override public void setAccelerator( KeyStroke keyStroke ) {
      super.setAccelerator( keyStroke );
      getInputMap( WHEN_IN_FOCUSED_WINDOW ).put( keyStroke, "none" );
   }

Вуаля!Нефункциональная комбинация клавиш, при этом текст подсказки в пункте меню остается нетронутым.


Однако лучшим решением моей первоначальной проблемы является изменение поведения всех сочетаний клавиш таким образом, чтобы они не запускайте, когда фокус клавиатуры находится внутри текстового компонента. Насколько я могу судить, это действительно единственная ситуация, когда (неизмененное) сочетание клавиш, такое как ПРОБЕЛ, столкнулось бы с поведением существующего компонента window.Это второе решение требует немного больше усилий, но оно лучше, потому что оно позволяет мне удалить весь мой другой пользовательский код для обработки сочетания клавиш, не устанавливая его в JMenuBar.

Вместо этого я могу просто использовать обычную архитектуру сочетаний клавиш в swing (т.е.установите его в JMenuBar или Action object) только с одним незначительным изменением:

Эта часть снова находится в пользовательском подклассе JMenuItem:

   /** {@inheritDoc} */
   @Override public void setAccelerator( KeyStroke keyStroke ) {
      super.setAccelerator( keyStroke );
      if ( doClickAction_ == null ) {
         doClickAction_ = new DoClickAction( getActionMap().get( "doClick" ) );
         getActionMap().put("doClick", doClickAction_);
      }
   }

И это новый частный внутренний класс в моем подклассе JMenuItem:

   /**
    * This action wraps the original "doClick" action for this menu item,
    * altering it so that it only fires if the keyboard focus is not in any
    * kind of text area or text field.
    * 

* Это позволяет добавлять клавиши ускорения в {@link IMenuItem}ы, * но пользователь все равно может вводить эти клавиши в текстовые компоненты без * запуска режима работы клавиши ускорения.*/ частный статический класс DoClickAction расширяет AbstractAction { // исходное действие, т.е.что мы завершаем частное заключительное действие doClickAction_;DoClickAction( Действие doClickAction ) { if ( doClickAction == null ) { выбросить новое исключение IllegalArgumentException();} doClickAction_ = документальное действие;} @Переопределить общедоступное недействительное выполненное действие ( ActionEvent e ) { окончательный KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();if ( kfm.getFocusOwner() экземпляр JTextComponent == false ) { doClickAction_.actionпереработано( e );} } }

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

Принимая во внимание ваше требование не прикасаться к коду L & F, в котором размещен текст ускорителя...

Просматривая код для JMenuItem, кажется , что вы могли бы создать подкласс JMenutItem для вашего элемента "пробел", который переопределил бы setAccelerator способ назначить нажатие клавиши акселератора, но не проходить через настройку действия.Это должно позволить коду пользовательского интерфейса выполнять свою работу по размещению меню так, как вам нравится, без неприятных действий, которые запускаются, когда ваши пользователи на самом деле пытаются поставить пробелы между своими словами (им действительно нужно это делать в любом случае?).

Я не знаю, являются ли текстовые компоненты единственным компонентом, который вызывает проблему.Если это так, то, возможно, вы можете просто настроить Действие так, чтобы использовать KeyboardFocusManager для определения, какой компонент в данный момент находится в фокусе.Если это текстовый компонент, то вы не вызываете свое действие.

Влияет ли настройка ускорителя на то, как вы все это реализовали в данный момент?Если нет, вы могли бы просто установить акселератор в положение пробела...Я собираюсь пойти дальше и предположить, что вы не можете этого сделать.Другая вещь, которую вы могли бы сделать, это переопределить getAccelerator() в вашем JMenuItem, поэтому вам не нужно копировать большую часть кода из JMenuItem (не то чтобы там было много).

JMenuItem clickSpace = new JMenuItem("Item With Accelerator Hint -->") {
        @Override
        public KeyStroke getAccelerator()
        {
            return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0);
        }
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top