动画化按钮移动实际上并不是最困难的问题,最困难的问题是试图将数据移动到可以管理的位置以及如何将源组件与目标连接起来.

首先,您需要一种可以跨容器边界移动组件的方法.虽然可能有几种方法可以做到这一点,但最简单的方法可能是使用框架的玻璃窗格

public class AnimationPane extends JPanel {

public AnimationPane() {

setOpaque(false);

setLayout(null);

}

}

这没什么特别的,它只是一个JPanel,它是透明的,没有布局管理器,通常不建议这样做,但是在这种情况下,我们将控制一切.

现在,我们需要某种方式来动画化运动.

public enum Animator {

INSTANCE;

private List 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调用更新.这种方法的目的是可以运行许多动画,但是由于只有一个更新/计时器点,因此不会(极大地)降低系统性能.

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,我们计算源组件的起点和目标点.然后,在每次调用更新时,我们都会计算动画的进度.我们不使用“增量”运动,而是计算开始时间与预定义的持续时间(在这种情况下为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);

}

}

}

java jbutton设置位置_java-将JButton设置为另一个JButton的位置相关推荐

  1. JAVA设置流中当前位置_Java程序来标记此输入流中的当前位置

    方法java.io.InputStream.mark()用于标记此输入流中的当前位置.该方法需要一个参数,即在标记位置无效之前可以读取的字节. 演示此的程序如下所示- 示例import java.io ...

  2. java 按钮设置图片_Java中如何设置带图片按钮的大小

    在java部分需要用到图形界面编程的项目中,经常会使用图片设置对按钮进行美化,但是使用时会出现一个很麻烦的问题, 按照方法:JButton jb1 = new JButton(); jb1.setBo ...

  3. java 设置字体_java里面怎样设置字体大小?

    import java.awt.Font; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JL ...

  4. java怎么调字体_java里面怎样设置字体大小?

    import java.awt.Font; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JL ...

  5. java 环境变量检测_java环境变量设置检测

    java环境变量设置检测 Java环境变量已经配置完了,不知道行不行,那么java环境变量设置检测呢?一起来看看吧! java环境变量设置检测 方法/步骤 首先,在桌面右击,选择"文本文档& ...

  6. java环境变量设置 成功_java环境变量设置

    java环境变量设置 java环境变量设置 首先,从Sun网站上下载jdk,当前版本为1_5_0_06(其他版本亦可) 最终下载下来的文件为jdk-1_5_0_06-windows-i586-p.ex ...

  7. java 设置超时_java线程超时设置方法

    对于java中线程超时间可以使用ExecutorService与Timer来控制一个线程什么时候超时了,下面我整理了一些方法,这些文章都详细的介绍java线程超时设置技巧. 方法一 本例子使用Exec ...

  8. java 多线程 cpu核数_java线程数设置和系统cpu的关系

    这里的cpu个数不是指系统的cpu总个数,也不是指cpu总核心数,而是指cpu的总逻辑处理单元即超线程的个数. IO密集型程序(如数据库数据交互.文件上传下载.网络数据传输等等)设置线程数为2倍的总逻 ...

  9. java 取系统环境变量_java获取和设置系统变量(环境变量)

    一.Java获取环境变量 Java 获取环境变量的方式很简单: System.getEnv()  得到所有的环境变量 System.getEnv(key) 得到某个环境变量 Map map = Sys ...

  10. java反射无法获取_Java反射'无法设置'错误

    我正在尝试使用Java反射来获取通用Field属性的实例,以便执行此Field的方法. 例如,如果我使用getValue()方法创建类型为MyType的类,并且我有另一个具有MyType类属性的MyC ...

最新文章

  1. 【TX2】英伟达Nvidia TX2连接蓝牙设备
  2. 爱上MVC~为DisplayNameFor添加扩展,支持PagedList集合
  3. android 剩余内存,Android:如何检查剩余的内存量?
  4. gunicorn 几种 worker class 性能测试比较
  5. PyTorch之实现LeNet-5卷积神经网络对mnist手写数字图片进行分类
  6. java nullexception_Java 中 NullPointerException 的完美解决方案
  7. AVL平衡树的插入例程
  8. 工具,帮助我们更高效的工作
  9. SpringMVC源码阅读:定位Controller
  10. 十八掌教育_徐培成_Hadoop3.0-01.简介
  11. uva 10780 分解质因数
  12. 一篇论文的正确格式是什么?
  13. linux skb 存放数据,请教关于在linux网络驱动层对skb网络数据..._网络编辑_帮考网...
  14. 光阴似锦,关于身体保养的那些事
  15. js 获取当前与一个月前的日期
  16. 快速识记会计中的借贷两方
  17. Chrome浏览器设置打开书签时在新标签页打开(保姆级图文)
  18. 数论的一个基础计算器,集成了同余式,逐次平方法,勒让德计算,模M的K次密等内容
  19. 甲级测绘资质审批常见问题-甲级测绘资质如何办理?
  20. [c语言]倒置字符串 -牛客网

热门文章

  1. 单片机数码管动态显示时钟C语言,8位数码管显示电子时钟c51单片机程序
  2. 利用PS 调整 pdf清晰度
  3. w10 http基本原理 Nginx部署
  4. java毕业设计(论文)答辩提纲,毕业论文答辩提纲模板.doc
  5. emwin emf格式视频生成环境搭建
  6. 主动微波遥感的测量原理
  7. 牛顿迭代法实现开根号
  8. html与css知识点集合
  9. 微信小程序 后端返回数据为字符串,转json方法
  10. fw300r虚拟服务器设置,迅捷(fast)fw300r路由器用手机怎么设置? | 192路由网