2015-04-15 45 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