2012-03-13 13 views
0

在Java中,當被拖動的項目是源控件本身時,執行拖放操作的最佳方式是什麼?我知道一個控制只不過是數據而已,但差異確實會影響UI。Java:如何將控件拖放到新位置而不是其數據?

我正在創建一個紙牌風格的遊戲,其中我有從JLabel派生的Card類卡對象。我想通過將其拖放到一個尚未命名的目標控件上來將該卡拖動到另一個位置。在拖動過程中,我希望卡片可以通過鼠標進行視覺移動,並且在丟棄時,我希望它移動到該目標對象或返回到其之前的位置。

我已經完成了各種D-n-D測試,並沒有發現任何在Java的D-D的適當規則下工作的東西。

例如,如果我使用真正的D-n-D拖動卡片對象,我只能創建卡片的幻影圖像而不是實體圖像。此外,光標變化,我寧願它沒有(我想我可以修復它),並且源代碼管理仍然可見(儘管在拖動過程中它應該很容易使其透明)

另一方面,我可以通過偵聽MouseMotionListener.mouseDragged()事件並手動將卡片移動到新位置來美觀地拖動卡片。這很好,但它不遵循正確的D-n-D,因爲這不會通知其他控件的拖動。我想我可以創建自己的系統來通知其他控件,但這不會使用Java的真正D-n-D。另外,如果我將真正的Java d-n-d東西與在mouseDragged期間逐字移動卡片的方法混合,那麼我認爲真正的D-n-D東西將永遠不會工作,因爲鼠標在技術上絕不會直接在除被卡的卡之外的任何其他控件上。這個方向看起來像是一個粗暴的黑客。

我希望這是有道理的。我之前一直在樣品上出現問題,因爲它們看起來都很不一樣,而我花了大量時間研究的樣品看起來要比D-n-D在1.4版本中進行大修之前要早幾年。

+0

的紙牌式的遊戲也許是更好看對於JList,Renderer默認爲retutns JLabel(或JComponent) – mKorbel 2012-03-13 22:36:40

+0

查看下面發佈的撲克牌示例。請讓我知道它是否有意義。 – 2012-03-14 01:48:00

回答

3

將組件拖放到單個應用程序而不是應用程序之間的一種方法是使用JLayeredPane。例如,請看看我的代碼在這裏:(!只要撲克牌圖像仍然有效)dragging a jlabel around the screen

撲克牌的例子看起來是這樣的:

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

import javax.imageio.ImageIO; 
import javax.swing.*; 

public class PlayingCardTest { 


    public static void main(String[] args) { 
     String pathToDeck = "http://www.jfitz.com/cards/classic-playing-cards.png"; 
     try { 
     final List<ImageIcon> cardImgList = CreateCards.createCardIconList(pathToDeck); 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       JFrame frame = new JFrame("Moving Cards"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new CardGameTable(cardImgList, frame)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
     } catch (MalformedURLException e) { 
     e.printStackTrace(); 
     System.exit(-1); 
     } catch (IOException e) { 
     e.printStackTrace(); 
     System.exit(-1); 
     } 
    } 
} 

@SuppressWarnings("serial") 
class CardGameTable extends JLayeredPane { 

    private static final int PREF_W = 600; 
    private static final int PREF_H = 400; 
    private static final Color BASE_COLOR = new Color(0, 80, 0); 
    private static final int CARD_COUNT = 20; 
    private static final int WIDTH_SHOWING = 20; 

    private JPanel basePane = new JPanel(null); 

    public CardGameTable(List<ImageIcon> cardImgList, final JFrame frame) { 
     basePane.setSize(getPreferredSize()); 
     basePane.setBackground(BASE_COLOR); 
     add(basePane, JLayeredPane.DEFAULT_LAYER); 

     final MyMouseAdapter myMouseAdapter = new MyMouseAdapter(this, basePane); 
     addMouseListener(myMouseAdapter); 
     addMouseMotionListener(myMouseAdapter); 

     for (int i = 0; i < CARD_COUNT; i++) { 
     JLabel card = new JLabel(cardImgList.remove(0)); 
     card.setSize(card.getPreferredSize()); 
     int x = (PREF_W/2) + WIDTH_SHOWING * (CARD_COUNT - 2 * i)/2 - 
       card.getPreferredSize().width/2; 
     int y = PREF_H - card.getPreferredSize().height - WIDTH_SHOWING * 2; 
     card.setLocation(x, y); 
     basePane.add(card); 
     } 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(PREF_W, PREF_H); 
    } 

} 

class MyMouseAdapter extends MouseAdapter { 
    private JLabel selectedCard = null; 
    private JLayeredPane cardGameTable = null; 
    private JPanel basePane = null; 
    private int deltaX = 0; 
    private int deltaY = 0; 

    public MyMouseAdapter(JLayeredPane gameTable, JPanel basePane) { 
     this.cardGameTable = gameTable; 
     this.basePane = basePane; 
    } 

    @Override 
    public void mousePressed(MouseEvent mEvt) { 
     Component comp = basePane.getComponentAt(mEvt.getPoint()); 
     if (comp != null && comp instanceof JLabel) { 
     selectedCard = (JLabel) comp; 
     basePane.remove(selectedCard); 
     basePane.revalidate(); 
     basePane.repaint(); 

     cardGameTable.add(selectedCard, JLayeredPane.DRAG_LAYER); 
     cardGameTable.revalidate(); 
     cardGameTable.repaint(); 
     deltaX = mEvt.getX() - selectedCard.getX(); 
     deltaY = mEvt.getY() - selectedCard.getY(); 
     } 
    } 

    @Override 
    public void mouseReleased(MouseEvent mEvt) { 
     if (selectedCard != null) { 
     cardGameTable.remove(selectedCard); 
     cardGameTable.revalidate(); 
     cardGameTable.repaint(); 

     basePane.add(selectedCard, 0); 
     basePane.revalidate(); 
     basePane.repaint(); 
     selectedCard = null; 
     } 
    } 

    @Override 
    public void mouseDragged(MouseEvent mEvt) { 
     if (selectedCard != null) { 
     int x = mEvt.getX() - deltaX; 
     int y = mEvt.getY() - deltaY; 
     selectedCard.setLocation(x, y); 
     cardGameTable.revalidate(); 
     cardGameTable.repaint(); 
     } 
    } 
} 

class CreateCards { 
    private static final int SUIT_COUNT = 4; 
    private static final int RANK_COUNT = 13; 

    public static List<ImageIcon> createCardIconList(String pathToDeck) 
     throws MalformedURLException, IOException { 
     BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck)); 
     int width = fullDeckImg.getWidth(); 
     int height = fullDeckImg.getHeight(); 
     List<ImageIcon> iconList = new ArrayList<ImageIcon>(); 

     for (int suit = 0; suit < SUIT_COUNT; suit++) { 
     for (int rank = 0; rank < RANK_COUNT; rank++) { 
      int x = (rank * width)/RANK_COUNT; 
      int y = (suit * height)/SUIT_COUNT; 
      int w = width/RANK_COUNT; 
      int h = height/SUIT_COUNT; 
      BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h); 
      iconList.add(new ImageIcon(cardImg)); 
     } 
     } 
     Collections.shuffle(iconList); 
     return iconList; 
    } 
} 
+0

哇,謝謝你的示例代碼,我現在正在挖掘它。我在一週前發現了JLayeredPane類,它讓生活變得輕鬆很多,但我想我只是抓住了它的表面。我已經可以告訴你沒有使用整個d-n-d/TransferHandler的東西,所以我猜這不是一個主要的Java人造移動,沒有官方的拖放東西。我有點擔心我的老網球老師的警告。她說,教完整新手網球比教練打球更容易,學過 – Shackleford 2012-03-14 02:14:50

+0

如何做到這一點是錯誤的,並且在接受再培訓之前需要未經訓練。我已經有了C++的經驗,但在4年之內並沒有觸及它。當我學習Java時,我決定小心翼翼地做,因此我沒有學習任何壞習慣,也沒有繼續留下我已經擁有的壞習慣。那時候我傾向於花費兩倍的努力去用我已經理解的技術來做事情,而不是花時間去學習從長遠來看可能使代碼更簡單的新技術。 – Shackleford 2012-03-14 02:19:15

相關問題