Как предотвратить перемещение курсора при обработке клавиши со стрелкой JScrollPane, когда панель прокрутки оборачивает текстовую панель

У меня есть следующие требования:

Мне нужна прокручиваемая JTextPane. Пользователь может ввести текст в эту текстовую область, или в нее может быть вставлен текст, который не был введен пользователем. Подумайте о чем-то вроде окна обмена мгновенными сообщениями. Хотя окно должно быть прокручиваемым, чтобы пользователь мог просмотреть ранее набранный текст, курсор никогда не должен перемещаться со своей позиции в конце текста. Любой текст, введенный пользователем, всегда будет отображаться в конце.

В JTextPane, когда пользователь прокручивает полосу прокрутки, курсор не перемещается. Область просмотра настроена. Однако, когда пользователь нажимает клавиши со стрелками вверх и вниз, курсор JTextPane перемещается вместе с ним (независимо от того, прокручивается окно или нет).

Я хочу, чтобы клавиша со стрелкой вверх функционировала так же, как перемещение полосы прокрутки вверх с помощью мыши. Клавиши со стрелками не должны иметь ничего общего с кареткой.

Я безуспешно пробовал следующие подходы: 1) добавить действие «Нет операции» в раскладку для моего класса текстовой панели (используя JTextPane.addKeymap() и Keymap.addActionForKeyStroke()). Это останавливает перемещение каретки, но предотвращает передачу действия на панель прокрутки для прокрутки представления. 2) удалить клавиши со стрелками из раскладки для моего класса текстовой панели. Это влияет на все JTextPanes в моем приложении, чего я не хочу.

Я хочу добавить действие к моей раскладке TextPane, которое просто вызывает действие ScrollPane для стрелок вверх и вниз.

Каков наилучший способ добиться этого?

Мне приходит в голову возможность реализовать KeyListener (который получает нажатие клавиши перед раскладкой), чтобы перехватывать эти клавиши, а затем выполнять прокрутку вручную. Но это, похоже, потребует от меня вычисления размеров шрифта и т. д. Есть ли более простой способ?

В идеале было бы, если бы был какой-то способ «привязать» курсор к любому концу текста.


person Steve Cohen    schedule 20.08.2012    source источник


Ответы (2)


Вам придется изменить KeyBindings

Попробуйте это для начала

InputMap im = textArea.getInputMap(WHEN_FOCUSED);
ActionMap am = textArea.getActionMap();

am.get("caret-down").setEnabled(false);
am.get("caret-up").setEnabled(false);

Теперь, когда у вас есть эта работа, вам нужно беспокоиться обо всех этих

selection-up = shift pressed UP
caret-next-word = ctrl pressed RIGHT
selection-previous-word = shift ctrl pressed LEFT
selection-up = shift pressed KP_UP
caret-down = pressed DOWN
caret-previous-word = ctrl pressed LEFT
caret-end-line = pressed END
selection-page-up = shift pressed PAGE_UP
caret-up = pressed KP_UP
delete-next = pressed DELETE
caret-begin = ctrl pressed HOME
selection-backward = shift pressed LEFT
caret-end = ctrl pressed END
delete-previous = pressed BACK_SPACE
selection-next-word = shift ctrl pressed RIGHT
caret-backward = pressed LEFT
caret-backward = pressed KP_LEFT
selection-forward = shift pressed KP_RIGHT
delete-previous = ctrl pressed H
unselect = ctrl pressed BACK_SLASH
insert-break = pressed ENTER
selection-begin-line = shift pressed HOME
caret-forward = pressed RIGHT
selection-page-left = shift ctrl pressed PAGE_UP
selection-down = shift pressed DOWN
page-down = pressed PAGE_DOWN
delete-previous-word = ctrl pressed BACK_SPACE
delete-next-word = ctrl pressed DELETE
selection-backward = shift pressed KP_LEFT
selection-page-right = shift ctrl pressed PAGE_DOWN
caret-next-word = ctrl pressed KP_RIGHT
selection-end-line = shift pressed END
caret-previous-word = ctrl pressed KP_LEFT
caret-begin-line = pressed HOME
caret-down = pressed KP_DOWN
selection-forward = shift pressed RIGHT
selection-end = shift ctrl pressed END
selection-previous-word = shift ctrl pressed KP_LEFT
selection-down = shift pressed KP_DOWN
insert-tab = pressed TAB
caret-up = pressed UP
selection-begin = shift ctrl pressed HOME
selection-page-down = shift pressed PAGE_DOWN
delete-previous = shift pressed BACK_SPACE
caret-forward = pressed KP_RIGHT
selection-next-word = shift ctrl pressed KP_RIGHT
page-up = pressed PAGE_UP
person MadProgrammer    schedule 20.08.2012
comment
Есть две проблемы с этим подходом (думаю - не пробовал). - person Steve Cohen; 21.08.2012
comment
Есть две проблемы с этим подходом (думаю - не пробовал). 1. Карта действий, полученная с помощью JTextArea.getActionMap(), является, как я полагаю, ССЫЛКОЙ на карту действий для всех JTextAreas, которая исходит из внешнего вида, поэтому это отключит команду для всех таких компонентов. 2. Недостаточно отключить ввод курсора вверх и вниз. Нам также нужно заставить нажатие клавиши реализовать ScrollPane.unitScrollUp и ScrollPane.unitScrollDown. Кажется, что многие из стандартного внешнего вида не продумали сценарий, в котором требуется режим работы без мыши. - person Steve Cohen; 21.08.2012
comment
Ваш первый пункт недействителен. Я использую эту технику все время, и она влияет только на экземпляр рассматриваемого объекта. В моем тесте, когда я нажимал вверх или вниз, курсор оставался на месте, но я мог прокручивать текстовую область, я не знаю, нужна ли вам эта функция или нет. В-третьих, с KeyListeners у вас нет возможности узнать, где именно в цепочке событий вас вызвали (или является ли эта цепочка одинаковой для всех ОС/внешнего вида) - person MadProgrammer; 21.08.2012
comment
Что ж, тогда я исправляюсь. Я должен буду попробовать это. Если это решение работает, это именно то, что я искал, и оно намного лучше, чем кладж KeyListener. Раньше я шел по тому же пути, но теперь я понимаю разницу. Я УДАЛЯЛ действия с карты действий, а вы просто отключили их. - person Steve Cohen; 22.08.2012
comment
Да, это колени пчел! - person Steve Cohen; 22.08.2012
comment
@SteveCohen Я подумал, что это довольно прикольно, когда я заставил его работать;) - person MadProgrammer; 22.08.2012
comment
Нет, на самом деле я удалял KeyStrokes из InputMap. Вместо этого мне нужно было отключить действия на ActionMap. Честно говоря, я никогда раньше не видел API Action.setEnabled()! - person Steve Cohen; 22.08.2012
comment
@SteveCohen Я давно хотел сделать это (удалить ввод/действия), но это такая изящная маленькая идея, что она потрясающая - person MadProgrammer; 22.08.2012

Что, если вы позволите пользователю поместить курсор, например. позволить ему выбрать и скопировать текст?

Я бы добавил DocumentFilter (или переопределил метод insertString() документа) и во всех случаях выполнил бы вставку в позицию doc.getLength() и сбрасывал курсор в позицию doc.getLength() после вставки.

person StanislavL    schedule 21.08.2012
comment
Этот компонент не поддерживает вырезание/копирование/вставку, поэтому этот ответ не имеет отношения к делу. - person Steve Cohen; 21.08.2012