且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JPanel setLocation

更新时间:2023-12-05 08:48:04

通过调用Thread.sleep,您可能会阻塞事件调度线程",该线程负责处理绘画请求.这意味着,直到您的循环实际完成为止,EDT将无法处理面板的更新位置.

By calling Thread.sleep, you are likely blocking the Event Dispatching Thread, which is responsible for, amongst other things, processing paint requests. This means until your loop actually finishes, the EDT won't be able to process the updated location of your panel.

相反,请使用javax.swing.Timer ...

Instead, use a javax.swing.Timer...

查看 Swing中的并发以了解更多详细信息

Check out Concurrency in Swing for more details

已更新

这是在FlowLayout btw下,因此我认为这可能与某些事情有关 用它,但不确定

This is under FlowLayout btw so I assume that may have something to do with it but am not sure

您正在与布局管理器作战,您会发现,一旦revalidate使用usePanel的容器,它将重新定位到布局管理器希望组件所在的位置.

You are fighting the layout manager, you will find that once you revalidate the container that usePanel is using, it will reposition back to where the layout manager wants the component to be.

尝试查看滑动布局,以获得更好的解决方案

Try taking a look at Sliding-Layout for an better solution

更新了一个基本示例

动画是随着时间变化的幻觉.在更新UI时,Swing对开发人员提出了一些相当严格的要求.

Animation is the illusion of change over time. Swing places some rather strict requirements on developers when it comes to updating the UI.

除了布局管理器之类的东西之外,Swing还要求对UI的所有交互和修改都必须在事件分发线程的上下文中进行.它还要求任何长时间运行或阻塞的进程都应在EDT以外的其他线程中执行.

Apart from things like layout managers, Swing requires that all interactions and modifications to the UI be done within the context of the Event Dispatching Thread. It also requires that any long running or block process be executed in another thread other than the EDT.

这使我们陷入了困境.22.我们需要在后台运行,因此我们不会阻止EDT处理绘画请求(除其他事项外),但是我们需要在EDT的上下文中更新组件. ...

This places us in a catch 22. We need to run in the background so we don't stop the EDT from processing paint requests (amongst other things), but we need to update our components from within the context of the EDT...

对我们来说幸运的是,有许多解决方案可用.最简单的问题是使用javax.swing.Timer

Lucky for us, there are a number of solutions available. The simplest to your problem would be the use of a javax.swing.Timer

此示例使用根窗格的玻璃窗格功能来提供覆盖的滑出,请参见如何使用根窗格了解更多详细信息.

This example uses the glass pane capabilities of the root pane to provide an overlying slide out, see How to use Root Panes for more details.

它也使用可变定时动画.也就是说,面板的位置基于动画中的时间进度,而不是某个固定的增量

It also uses a variable timed animation. That is, the position of the panel is based on the progression of time through the animation rather than some fixed delta

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class SlidingPane {

    private SlidePane slidePane = new SlidePane();

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

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

                JButton slideButton = new JButton("Slide");
                slideButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        slidePane.slide();
                    }
                });

                JFrame frame = new JFrame("Testing");

                JPanel glassPane = new JPanel(null);
                glassPane.setOpaque(false);
                glassPane.add(slidePane);
                frame.setGlassPane(glassPane);
                glassPane.setVisible(true);

                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                frame.add(new JLabel("Look ma, no hands!"), gbc);
                frame.add(slideButton, gbc);
                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SlidePane extends JPanel {

        private long startTime = -1;
        private int runTime = 1000;
        private int startX;
        private int targetX;
        private boolean slideIn = false;
        private Timer slideTimer;

        public SlidePane() {
            setBackground(Color.DARK_GRAY);
            setBorder(new LineBorder(Color.BLACK));
            setLocation(-getPreferredSize().width, 0);
            setLayout(new GridBagLayout());
            JLabel label = new JLabel("I'm your overload");
            label.setForeground(Color.WHITE);
            add(label);
            slideTimer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    long diff = System.currentTimeMillis() - startTime;
                    double progress = (double)diff / (double)runTime;
                    if (progress >= 1d) {
                        progress = 1d;
                        slideTimer.stop();
                        startTime = -1;
                    }

                    Container parent = getParent();
                    int height = parent.getHeight();
                    setSize(getPreferredSize().width, height);

                    int x = calculateProgress(startX, targetX, progress);
                    setLocation(x, 0);
                    revalidate();
                    repaint();
                }
            });
        }

        protected int calculateProgress(int startValue, int endValue, double fraction) {

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

            return value;

        }

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

        public void slide() {

            slideTimer.stop();
            startTime = System.currentTimeMillis();

            slideIn = !slideIn;
            startX = getX();
            targetX = 0;
            if (!slideIn) {
                targetX = -getPreferredSize().width;
            }

            slideTimer.start();

        }
    }
}