我對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