【问题标题】:Smooth motion for JPanel and update JLabel at same timeJPanel 的平滑运动和同时更新 JLabel
【发布时间】:2019-04-08 07:50:03
【问题描述】:

如何平滑移动JPanel并同时更新JLabel

我想在JFrame 上显示当前时间,所以我创建了一个新的java.util.Timer 并每隔一秒更新一次标签。

我还创建了另一个 Java 线程来移动面板组件。

但在移动面板并在框架上显示(更新)时间时,面板会刷新以形成原始位置。

所以我在 Google 中搜索该问题并找不到解决方案。

//Code to move jPanel smoothly
        Thread t = new Thread(){
            int i = 0 ;
            public void run(){
                while(i<150){
                    i++;
                    jPanel2.setLocation(i, jPanel2.getY());
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException ex) {
                    }
                }
            }
        };
        t.start();

// Code to show Time
       Timer t = new javax.swing.Timer(1, new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                jLabel1.setText(new Date()+"");
            }
        });
        t.start();

【问题讨论】:

  • 1) 永远不要从另一个线程更新 Swing 组件。始终使用javax.swing.Timer 2) 1 表示计时器意味着 1 毫秒而不是 1 秒。 3) 请提供一个小型可运行类 (minimal reproducible example),以便我们重现您的问题。
  • 所以我需要更改 Thread 而不是 javax.swing.timer 才能顺利移动 jPanel?
  • 您需要 2 个 javax.swing.Timer 对象。一个用于更新时钟标签,另一个用于机芯。在第二个计时器中,您还需要重新绘制移动组件的父级。
  • 但它仍然无法完美运行。 :(
  • 您的问题需要edit而不是start a new one!请阅读@SergiyMedvynskyy 链接的页面,因为上面的不可编译代码sn-p 不是 MCVE。

标签: java multithreading swing animation


【解决方案1】:

这是一个小例子,如何为组件提供动画和更新。

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;

/**
 * <code>MovedClock</code>.
 */
public class MovedClock {

    private final JLabel clock = new JLabel();
    private final DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm:ss");

    private void startUI() {
        JFrame frame = new JFrame("Moved clock");
        frame.setLayout(null); // usually it's a bad idea, but for animation we need this.
        clock.setBounds(0, 50, 50, 20);
        frame.add(clock);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(500, 200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        updateClock();
        Timer clockTimer = new Timer(1000, e -> updateClock());
        clockTimer.start();
        // 15 milliseconds for about 60fps
        Timer moveTimer = new Timer(15, new ActionListener() {

            private int count = 1;

            private int increment = 1;

            @Override
            public void actionPerformed(ActionEvent e) {
                if (count == 435 || count == 0) {
                    increment = -increment;
                }
                Point loc = clock.getLocation();
                loc.x += increment;
                clock.setLocation(loc);
                count += increment;
            }
        });
        moveTimer.start();
    }

    private void updateClock() {
        clock.setText(LocalTime.now().format(format));
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new MovedClock()::startUI);
    }
}

【讨论】:

  • 但是如何在 jLabel 到达 JFrame 末尾后停止 actionPerform 事件
  • @JianShangQuan 将increment = -increment; 行替换为((Timer) e.getSource()).stop(); 语句。在这种情况下,当标签位于行尾时,移动将停止。
猜你喜欢
  • 1970-01-01
  • 2014-11-13
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 1970-01-01
相关资源
最近更新 更多