У меня есть вопрос, касающийся скорости обратного вызова mouseDragged
сообщения MouseMotionListener
в Java Swing. Этот пост в некотором роде связан, но не совсем так, поэтому я начал собственный вопрос.
Я делаю небольшое внутреннее приложение, не обращая внимания на коммерческое распространение, котороев основном это цифровой эмулятор TCG (Trading Card Game).Для любого из вас, знакомых с MtG (Magic the Gathering), вы могли слышать о такой похожей программе.Я пытаюсь создать что-то похожее на this , но менее навороченное.
Мой GUI состоит из JFrame с меню, а затем некоторых панелей, содержащих различные кнопки и метки, но яЯ расскажу только о соответствующих частях, чтобы объяснить мою проблему.
В сущности, я использую вертикальное разбиение JSplitPane
с JPanel
слева, в котором JScrollPane
сJList
в нем, который в любое время представляет карты в вашей руке, в которые вы можете играть.На правой стороне разделения у меня есть JLayeredPane
с фоновым изображением в DEFAULT_LAYER
(подкласс JPanel
, который переопределяет функцию draw
для добавления изображения) и на различных слоях выше PALETTE_LAYER
, Я отображаю карты, которые находятся в игре (собранные в ArrayList
) с помощью пользовательских CardPanel
s (другой подкласс JPanel
, который иллюстрирует карту).Таким образом, весь JLayeredPane
представляет собой стол перед вами со всеми картами, которые вы уже разыграли.
Сначала я добавил MouseListener
и MouseMotionListener
к * 1030.* чтобы забрать события, позволяя мне зарегистрировать нажатие мыши, проверить, было ли это выше карты, затем использовать событие перетаскивания мышью, чтобы переместить карту, и, наконец, отпустить кнопку мыши, чтобы вернуть ее обратно.Все это прекрасно работает, и если я добавлю информацию о регистрации, я вижу, что функция обратного вызова mouseDragged
часто вызывается, что позволяет визуально быстро перемещать движение без задержки.
Сегодня я решил добавить функциональность, чтобы позволить пользователюперетащить карту из его руки в «стол» (вместо двойного щелчка по карте в JList
), поэтому я добавил соответствующих слушателей в JList
вместе с заполнением некоторых функций, таких как MousePressed
и MouseReleased
.При нажатии мыши я проверяю, какая карта из списка была нажата, я блокирую список, создаю пользовательский CardPanel
(но пока никуда его не добавляю, я просто выделяю и инициирую его!) И устанавливаю флаг.При перетаскивании мышью я проверяю, установлен ли этот флаг.Если это так, я проверяю, где находится курсор.Если оно где-то выше JLayeredPane
, я добавляю CardPanel
к DRAG_LAYER
и устанавливаю другой флаг.Если этот второй флаг установлен в последовательных вызовах при перетаскивании мышью, я больше не добавляю панель, а просто меняю местоположение.Эта функциональность практически такая же, как в предыдущей функции перетаскивания мышью.При отпускании мыши я разблокирую список и добавляю CardPanel
на правильный слой в JLayeredPane
.
Все работает, как задумано, поэтому я почти уверен, что мой код в порядке, но есть толькоодна небольшая проблема:
При перетаскивании карты из списка на многоуровневую панель (вместо многоуровневой панели на многоуровневую панель) я замечаю, что обратный вызов mouseDragged
вызывается с довольно низкой частотойJList
(примерно 10 раз в секунду), вводя некоторое визуально мешающее запаздывание (по сравнению с примерно 30 разами в секунду в первом случае перетаскивания).
Я собираюсь добавить некоторые фрагменты кода, чтобы уточнитьмоя проблема, но я боюсь, что добавление всего кода, чтобы вы могли запустить его самостоятельно, было бы серьезным излишним.
Основной вопрос в этом посте: кто-нибудь знает, почему mouseDragged
вызывается быстрее однимMouseMotionListener
чем другим MouseMotionListener
?Слушатель компонента JLayeredPane
делает быстрые последовательные вызовы, слушатель вызовов JList
значительно медленнее.
Примечание: Я занимаюсь разработкой в Netbeans и используювстроенный графический Swing Interface Builder.Я использую форму JFrame в качестве основного класса.
public class MyFrame extends JFrame{
...
protected JLayeredPane layeredPane;
protected JList cardsInHandList;
...
...
protected ArrayList<String> cardsInHand;
...
private void attachListeners(){
layeredPane.addMouseListener(new MouseAdapter(){
public void MousePressed(MouseEvent e){
// set a flag, start a drag
}
public void MouseReleased(MouseEvent e){
// unset a flag, stop a drag
}
});
layeredPane.addMouseMotionListener(new MouseMotionAdapter(){
public void MouseDragged(MouseEvent e){
// drag the card around
// gets called a lot!
// actual code:
if (e.getButton() == MouseEvent.BUTTON1) {
if (!dragging) return; // the flag
int x = e.getX() - 10;
int y = e.getY() - 10;
// snap to grid
x /= GRIDX;
x *= GRIDX;
y /= GRIDY;
y *= GRIDY;
// redraw the card at its new location
draggedCard.setLocation(x, y);
}
}
});
cardsInHandList.addMouseListener(new MouseAdapter(){
public void MousePressed(MouseEvent e){
// set a flag, start a drag
}
public void MouseReleased(MouseEvent e){
// unset a flag, stop a drag
}
});
cardsInHandList.addMouseMotionListener(new MouseMotionAdapter(){
public void MouseDragged(MouseEvent evt){
// check cursor location, drag if within bounds of layeredPane
// gets called a whole lot less!! _Why?_
// actual code:
if (!draggingFromHand) return; // the flag
// check location of cursor with own method (contains() didn't work for me)
if (isCursorAtPointAboveLayeredPane(evt.getLocationOnScreen())) {
// calculate where and snap to grid
int x = (int) (evt.getLocationOnScreen().getX() - layeredPane.getLocationOnScreen().getX())-10;
int y = (int) (evt.getLocationOnScreen().getY() - layeredPane.getLocationOnScreen().getY())-10;
// snap to grid
x /= GRIDX;
x *= GRIDX;
y /= GRIDY;
y *= GRIDY;
if(!draggingFromHandCardPanelAdded){
layeredPane.add(draggingFromHandCardPanel, JLayeredPane.DRAG_LAYER);
draggingFromHandCardPanelAdded = true;
} else {
draggingFromHandCardPanel.setLocation(x,y);
}
}
}
});
}
Я попытаюсь создать короткий исполняемый пример, воспроизводящий проблему, а затем прикрепить код куда-нибудь, но сейчас я должен skoot.
Заранее спасибо
PS : я знаю, что в Java есть еще один способ перетаскивания, включающий TransferHandlers и все такое, но это просто кажется слишком хлопотным, и это не реальный ответ на мой вопрос о том, как получается, что один обратный вызов кажется вызваннымбольше, чем другие, поэтому, пожалуйста, не говорите мне использовать это вместо этого.