我对Java Swing中MouseMotionListener
的mouseDragged
消息的回调速度有一个问题。 This post是有点相关,但它不完全相同,所以我开始了我自己的问题。Java Swing mouseDragged回调速度
我正在制作一个小型的内部应用程序,没有关注基本上是数字化TCG(交易卡片游戏)模拟器的商业分布。对于任何你熟悉MtG(万智牌)的人,你可能听说过这样一个类似的计划。我正在尝试创建一些看似有点像this的东西,但不那么花哨。
我的GUI由一个带菜单的JFrame组成,然后是一些包含各种按钮和标签的面板,但我只会讲解相关部分来解释我的问题。
从本质上说,我使用的是垂直分割JSplitPane
在左边一JPanel
,在一个JScrollPane
与JList
在里面,它代表随时在你手里的牌,你可以玩。在分割的右侧,我有一个JLayeredPane
,其中DEFAULT_LAYER
(JPanel
的子类别覆盖draw
函数添加图像)中的背景图像,并在PALETTE_LAYER
上方的各个图层上显示正在播放的卡片(收集在ArrayList
中)通过定制CardPanel
(表示卡的另一个子类JPanel
)进行。因此,整个JLayeredPane
就是你前面牌桌上所有你已经玩过的牌的代表。
我第一次加入了MouseListener
和MouseMotionListener
到JLayeredPane
回暖的事件,让我注册一个按下鼠标,检查,如果这是上面的一张牌,然后用鼠标拖动事件四处移动卡开始,最后鼠标释放将其放回。这一切都工作得很好,如果我添加日志记录信息,我可以看到mouseDragged
回调函数经常被调用,允许视觉快速拖动运动没有滞后。
今天我决定添加功能,允许用户从他的手中将卡片拖到“桌子”(而不是双击JList
中的卡片),所以我将适当的听众与JList
一起添加到填写一些功能,如MousePressed
和MouseReleased
。在鼠标按下时,我检查列表中的卡片是否被点击,我锁定列表,创建自定义CardPanel
(但不要将它添加到任何地方,我只是分配并启动它!)并设置一个标志。在拖动的鼠标中,我检查是否设置了该标志。如果是,我检查光标在哪里。如果它位于JLayeredPane
以上的任何位置,我将CardPanel
添加到DRAG_LAYER
并设置另一个标志。如果在连续调用拖动鼠标时设置了第二个标志,我不会再次添加面板,但我只是更改位置。该功能与我之前鼠标拖动回调中的功能几乎相同。在鼠标释放时,我解锁列表并在JLayeredPane
的正确图层上添加CardPanel
。
一切如预期运行,所以我敢肯定我的代码是好的,但只有一个轻微的问题:
当从列表中拖动卡的分层窗格(而不是从分层窗格我注意到mouseDragged
回调被JList
(约每秒10次)的相当低的频率调用,引入了一些视觉上令人不安的滞后(相比之下,在第一种情况下每秒约30次)。
我要添加一些代码片段来澄清我的问题,但是我害怕添加所有代码以允许您自己运行它会是严重的过度消耗。
在这篇文章中的主要问题是:有谁知道为什么mouseDragged
被称为更快一个MouseMotionListener
比另一个MouseMotionListener
?对JLayeredPane
组件的收听者进行快速连续呼叫,呼叫的收听者显着更慢。
注:我在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和所有的,但它只是似乎有太多的麻烦,这是不是一个实际的答案我的一个回调似乎被称为比其他更多的问题,所以请不要告诉我使用它。
也许我拆分到4分离的问题,因为很难回答,由@Hovercraft全鳝也许伟大的职位可以帮助你一个从第15个问题,我看到那里 http://stackoverflow.com/search?q=user%3A522444+DragLabelOnLayeredPane – mKorbel 2011-12-17 17:28:43