2015-04-15 72 views
1

我試圖將JButton移到另一個位置,但是我想移動的按鈕移動到錯誤的位置。我的想法是,這是因爲我使用多個JPanel。我試過:getLocationOnScreen,getBoundsgetLocation,但是他們都沒有工作,該如何解決?當用戶通過點擊該卡片選擇卡片或玩家通過點擊該卡片設置目標時,通過點擊頂部面板上的卡片來設置發送者。 playerCardSpotTargetplayerCardSpotSender都是卡類型。當我嘗試移動八顆鑽石時,這張卡移動到八個和九個俱樂部後面的一點。將JButton設置爲另一個JButton的位置

enter image description here

代碼:

此事件屬於桌子上的藍卡和卡的玩家(我不得不改變事件的名字,我知道)。

private void PlayerOneMouseClicked(java.awt.event.MouseEvent evt){ 
    playerCardSpotTarget=(Card)evt.getSource();   

    if(playerCardSpotTarget.isBorderPainted()){ 
     playerCardSpotTarget.setBorderPainted(false); 
    } 
    else{ 
     playerCardSpotTarget.setBorderPainted(true); 
    } 
} 

此事件屬於頂部面板中的卡片。

private void MouseClicked(java.awt.event.MouseEvent evt) {        
    playerCardSpotSender=(Card)evt.getSource(); 

    System.out.println(playerCardSpotSender.suit+" "+playerCardSpotSender.kind); 


    if (playerCardSpotTarget != null && playerCardSpotTarget.isBorderPainted()) {    

     playerCardSpotSender.setLocation(playerCardSpotTarget.getLocation()); 
     System.out.println(playerCardSpotTarget.getLocationOnScreen()); 
     System.out.println(playerCardSpotSender.getLocationOnScreen()); 

    } 
} 

佈局中的JFrame(BorderLayout.CENTER)中心面板

JPanel centerPanelNorth; 
    JPanel centerPanelCenter; 
    JPanel centerPanelEast; 
    JPanel centerPanelSouth; 
    JPanel centerPanelWest; 
    JLabel tablePicture; 
    JPanel centerPanel; 


    centerPanel=new JPanel(new BorderLayout()); 
    tablePicture = new JLabel(new ImageIcon(this.getClass().getResource(Constants.POKERTABLE_ICON))); 
    centerPanelNorth=new JPanel(); 
    centerPanelEast=new JPanel(); 
    centerPanelSouth=new JPanel(); 
    centerPanelWest=new JPanel(); 

    centerPanelCenter=new JPanel(); 

    centerPanel.add(centerPanelCenter,BorderLayout.CENTER); 

    centerPanelCenter.add(tablePicture); 

    //add 
    tablePicture.add(boardCard1); 
    tablePicture.add(boardCard2); 
    tablePicture.add(boardCard3); 
    tablePicture.setLayout(new GridBagLayout()); 

    //PLAYER NORTH 
    centerPanel.add(centerPanelNorth,BorderLayout.NORTH); 
    centerPanelNorth.add(playerOneCardOne); 
    centerPanelNorth.add(playerOneCardTwo); 

    //PLAYER EAST 
    centerPanel.add(centerPanelEast,BorderLayout.EAST); 
    centerPanelEast.setLayout(new BoxLayout(centerPanelEast,BoxLayout.X_AXIS)); 
    centerPanelEast.add(playerTwoCardOne); 
    centerPanelEast.add(playerTwoCardTwo); 

    //PLAYER SOUTH 
    centerPanel.add(centerPanelSouth,BorderLayout.SOUTH); 
    centerPanelSouth.add(playerThreeCardOne); 
    centerPanelSouth.add(playerThreeCardTwo); 

    //PLAYER WEST 
    centerPanel.add(centerPanelWest,BorderLayout.WEST); 
    centerPanelWest.setLayout(new BoxLayout(centerPanelWest,BoxLayout.X_AXIS)); 
    centerPanelWest.add(playerFourCardOne); 
    centerPanelWest.add(playerFourCardTwo); 

Card.java

public class Card extends JButton{ 
    int suit; 
    int kind; 
    boolean known; 
    String iconPath; 
    Integer boardPosition; 
} 
+0

爲什麼要移動按鈕,爲什麼不移動信息N + – MadProgrammer

+0

@MadProgrammer我也會移動信息,但首先我正在努力移動卡片,以便爲用戶提供關於發生什麼事情的直觀表示。我怎樣才能移動按鈕? – Sybren

+0

你想要動畫嗎?或者你只是想讓第一個內容更新其他按鈕? – MadProgrammer

回答

0

也許使用mousePressed(),當你移動的卡,你按下它直到目標爲止。並且在這個過程中,你通過事件獲得了關於JButton.getLocation()的信息,並且比你需要解決兩張卡片之間的碰撞問題。所以這很好!當然,這是我的建議,你應該有更好的主意!

+0

我喜歡加/受mouseclicking而不是拖/放取出卡,你知道如何要做到這一點? – Sybren

+0

當你不需要它,調用'JPanel.remove()',所以這將是disappear.But使用這一點,你需要考慮分層issue.Sometimes,你畫它,但你不能看到它。 – Seven

+0

我需要JPanel。 – Sybren

1

動畫按鈕動作實際上不是最難的問題,最難的問題是試圖移動數據約在客場中,你可以管理它,以及如何將源組件與目標連接...

Move me

首先,您需要一種方法,通過該方法可以跨組件邊界移動組件。雖然有可能是幾個方法可以做到這一點,最簡單的就是可能使用幀

public class AnimationPane extends JPanel { 

    public AnimationPane() { 
     setOpaque(false); 
     setLayout(null); 
    } 

} 

它沒有什麼特別的玻璃面板,它只是一個JPanel這是透明的,沒有佈局管理器,通常情況下,不推薦使用,但在情況下,我們要採取控制..

現在,我們需要一些方法來製作動畫的運動...

public enum Animator { 

    INSTANCE; 

    private List<IAnimatable> animatables; 

    private Timer timer; 

    private Animator() { 
     animatables = new ArrayList<>(25); 
     timer = new Timer(40, new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      IAnimatable[] anins = animatables.toArray(new IAnimatable[animatables.size()]); 
      for (IAnimatable animatable : anins) { 
      animatable.update(); 
      } 
     } 
     }); 
     timer.start(); 
    } 

    public void addAnimatable(IAnimatable animatable) { 
     animatables.add(animatable); 
    } 

    public void removeAnimatable(IAnimatable animatable) { 
     animatables.remove(animatable); 
    } 

    } 

    public interface IAnimatable { 

    public void update(); 

    } 

    public interface IMoveAnimatable extends IAnimatable{ 

    public JComponent getSourceComponent(); 

    public IImportable getImportable(); 

    } 

所以Animator是核心「引擎」 ,它基本上是一個Swing Timer,它只需在IAnimatable上調用update即可管理。這種方法的意圖是你可以運行一些動畫,但是它不會降低系統(很大程度上),因爲你只有一個更新/定時器點。

現在,通常我只是使用類似Timing FrameworkTrident Framework甚至Universal Tween Engine

IAnimatable接口只是定義爲動漫提供功能的基本合同。

我們需要定義某種契約的可參與動畫製作過程和接收信息的定義對象,或者「目標」

public interface IImportable { 
    public JComponent getView(); 
    public void importValue(String value); 
} 

public abstract class AbstractImportable extends JPanel implements IImportable { 

    @Override 
    public JComponent getView() { 
     return this; 
    } 

} 

現在它發生,我認爲我們可以挖掘到預先存在Transferable API,它允許您也實現拖放(甚至複製/剪切和粘貼),這將用於定義一種查找機制,在該機制中,您將給定數據類型與潛在目標進行匹配,基於DataFlavor ...但我會離開你去研究它是如何工作的...... 核心機制基本上從當前容器中移除源組件,將它添加到AnimationPane,將源組件移動到AnimationPane上,然後將數據導入到目標中...

問題是,您需要將組件的位置從當前上下文轉換爲AnimationPane

組件的位置是相對於它的父母上下文。使用SwingUtilities.convertPoint(Component, Point, Component)

我們計算源組件和目標點的原點,相對於AnimationPane。然後,我們在每次致電update時計算動畫的進度。代替使用「增量」的運動,我們計算我們開始的時間和預定的持續時間(即1秒在這種情況下)之間的不同,這通常產生了更靈活的動畫

public class DefaultAnimatable implements IMoveAnimatable { 

    public static final double PLAY_TIME = 1000d; 

    private Long startTime; 
    private JComponent sourceComponent; 
    private IImportable importable; 
    private JComponent animationSurface; 

    private Point originPoint, destinationPoint; 

    private String value; 

    public DefaultAnimatable(JComponent animationSurface, JComponent sourceComponent, IImportable importable, String value) { 
     this.sourceComponent = sourceComponent; 
     this.importable = importable; 
     this.animationSurface = animationSurface; 
     this.value = value; 
    } 

    public String getValue() { 
     return value; 
    } 

    public JComponent getAnimationSurface() { 
     return animationSurface; 
    } 

    @Override 
    public JComponent getSourceComponent() { 
     return sourceComponent; 
    } 

    @Override 
    public IImportable getImportable() { 
     return importable; 
    } 

    @Override 
    public void update() { 
     if (startTime == null) { 
     System.out.println("Start"); 
     IImportable importable = getImportable(); 
     JComponent target = importable.getView(); 

     originPoint = SwingUtilities.convertPoint(getSourceComponent().getParent(), getSourceComponent().getLocation(), getAnimationSurface()); 
     destinationPoint = SwingUtilities.convertPoint(target.getParent(), target.getLocation(), getAnimationSurface()); 

     destinationPoint.x = destinationPoint.x + ((target.getWidth() - getSourceComponent().getWidth())/2); 
     destinationPoint.y = destinationPoint.y + ((target.getHeight() - getSourceComponent().getHeight())/2); 

     Container parent = getSourceComponent().getParent(); 

     getAnimationSurface().add(getSourceComponent()); 
     getSourceComponent().setLocation(originPoint); 

     parent.invalidate(); 
     parent.validate(); 
     parent.repaint(); 

     startTime = System.currentTimeMillis(); 
     } 
     long duration = System.currentTimeMillis() - startTime; 
     double progress = Math.min(duration/PLAY_TIME, 1d); 

     Point location = new Point(); 
     location.x = progress(originPoint.x, destinationPoint.x, progress); 
     location.y = progress(originPoint.y, destinationPoint.y, progress); 

     getSourceComponent().setLocation(location); 
     getAnimationSurface().repaint(); 

     if (progress == 1d) { 
     getAnimationSurface().remove(getSourceComponent()); 
     Animator.INSTANCE.removeAnimatable(this); 
     animationCompleted(); 
     } 
    } 

    public int progress(int startValue, int endValue, double fraction) { 

     int value = 0; 
     int distance = endValue - startValue; 
     value = (int) Math.round((double) distance * fraction); 
     value += startValue; 

     return value; 

    } 

    protected void animationCompleted() { 
     getImportable().importValue(getValue()); 
    } 

    } 

好,現在這產生一個線性動畫,這是很無聊,現在如果你有足夠的時間,你可以創建一個地役權,如this或只是使用其中一個動畫框架...

現在,我們需要把它放在一起...

import java.awt.BorderLayout; 
    import java.awt.Color; 
    import java.awt.Container; 
    import java.awt.Dimension; 
    import java.awt.EventQueue; 
    import java.awt.GridBagLayout; 
    import java.awt.GridLayout; 
    import java.awt.Point; 
    import java.awt.event.ActionEvent; 
    import java.awt.event.ActionListener; 
    import java.util.ArrayList; 
    import java.util.List; 
    import javax.swing.JButton; 
    import javax.swing.JComponent; 
    import javax.swing.JFrame; 
    import javax.swing.JPanel; 
    import javax.swing.SwingUtilities; 
    import javax.swing.Timer; 
    import javax.swing.UIManager; 
    import javax.swing.UnsupportedLookAndFeelException; 
    import javax.swing.border.LineBorder; 

    public class AnimationTest { 

    public static void main(String[] args) { 
     new AnimationTest(); 
    } 

    public AnimationTest() { 
     EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      try { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
      ex.printStackTrace(); 
      } 

     AnimationPane animationPane = new AnimationPane(); 

      LeftPane leftPane = new LeftPane(animationPane); 
      RightPane rightPane = new RightPane(); 

      leftPane.setImportabale(rightPane); 
      rightPane.setImportabale(leftPane); 

      JFrame frame = new JFrame("Testing"); 
      frame.setLayout(new GridLayout(1, 2)); 
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      frame.add(leftPane, BorderLayout.WEST); 
      frame.add(rightPane, BorderLayout.WEST); 
      frame.setGlassPane(animationPane); 
      animationPane.setVisible(true); 
      frame.pack(); 
      frame.setLocationRelativeTo(null); 
      frame.setVisible(true); 
     } 
     }); 
    } 

    public class RightPane extends AbstractImportable { 

     private IImportable source; 
     private JButton imported; 

     private String importedValue; 

     public RightPane() { 
     setLayout(new GridBagLayout()); 
     setBorder(new LineBorder(Color.DARK_GRAY)); 
     } 

     public void setImportabale(IImportable source) { 
     this.source = source; 
     } 

     @Override 
     public void importValue(String value) { 
     if (imported != null) { 
      // May re-animate the movement back... 
      remove(imported); 
     } 
     importedValue = value; 
     imported = new JButton(">> " + value + "<<"); 
     add(imported); 
     revalidate(); 
     repaint(); 
     } 

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

    } 

    public class LeftPane extends AbstractImportable { 

     private IImportable importable; 

     public LeftPane(AnimationPane animationPane) { 
     setLayout(new GridBagLayout()); 
     JButton btn = new JButton("Lefty"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
      DefaultAnimatable animatable = new DefaultAnimatable(animationPane, btn, importable, "Lefty"); 
      Animator.INSTANCE.addAnimatable(animatable); 
      } 
     }); 

     add(btn); 
     setBorder(new LineBorder(Color.DARK_GRAY)); 
     } 

     public void setImportabale(IImportable target) { 
     this.importable = target; 
     } 

     @Override 
     public void importValue(String value) { 
     } 

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

    } 
    } 
+0

我解決了這個問題,通過刪除按鈕並將其添加到另一個面板 – Sybren