JPanels的负坐标(与Timer无法合作)

时间:2016-07-25 13:25:55

标签: java swing jpanel

请注意,这是一个关于这种方法问题的更理论性的问题,因为我试图理解潜在的机制 - 真正的好奇心。对于实际的实现,我可能会使用不同的东西。

假设我们在拆分窗格中有以下框架。分割窗格的右侧有一个按钮,用于滑出左侧的面板并在其位置显示另一个面板(此处我使用覆盖布局使其看起来更平滑)。代码如下:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.OverlayLayout;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Main {

   JPanel panel;
   JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
   public void makeUI() {

      panel = new JPanel();
      panel.setBackground(Color.RED);
      panel.setLocation(0,0);
      JPanel panel3 = new JPanel();
      panel3.setBackground(Color.BLUE);
      panel3.setMinimumSize(new Dimension(100,400));

      JPanel panelContainer = new JPanel();
      panelContainer.setLayout(new OverlayLayout(panelContainer));
      panelContainer.add(panel);
      panelContainer.add(panel3);


      JButton button = new JButton("slide out");
      // Slide out the red panel to reveal blue
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            ((JButton) e.getSource()).setEnabled(false);
            new Timer(1, new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                  panel.setLocation(panel.getX() - 1, 0);
                  if (panel.getX() + panel.getWidth() == 0) {
                     ((Timer) e.getSource()).stop();
                     panel.setVisible(false);
               System.out.println("Timer stopped");
            }
               }
            }).start();
         }
      });

      JFrame frame = new JFrame("Sliding Panel");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(400, 400);
      frame.setLocationRelativeTo(null);
      frame.setLayout(null);

      splitPane.setDividerLocation(100);
      splitPane.setLeftComponent(panelContainer);
      JPanel panel2 = new JPanel();
      panel2.add(button);
//      panel2.add(button2);
      panel2.setMinimumSize(new Dimension(200,400));
      splitPane.setRightComponent(panel2);
      frame.setContentPane(splitPane);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            new Main().makeUI();
         }
      });
   }
}

现在,如果我添加一个反转动画的按钮,通过将位置设置为(-panel.getWidth(), 0)然后增加x坐标,则会失败。理论上,代码是相同的,唯一的区别在于起始位置,结束位置和增量。但它不再起作用。

  JButton button2 = new JButton("slide in");
  button2.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
        ((JButton) e.getSource()).setEnabled(false);
        panel.setVisible(true);
        panel.setLocation(-panel.getWidth(),0);
        System.out.println(panel.getX()); // gives -99, which is about right
        new Timer(1, new ActionListener() {
           public void actionPerformed(ActionEvent e) {
               System.out.println(panel.getX()); // starts from 0
              panel.setLocation(panel.getX() + 1, 0);
              System.out.println(panel.getX()); // keeps increasing until forcibly stopped
              if (panel.getX() == 0) {
                 ((Timer) e.getSource()).stop();
           System.out.println("Timer stopped");
        }
           }
        }).start();
     }
  });

更确切地说,问题在于new Timer(...)行。根据控制台日志记录,设置位置将X坐标置于-99,但两行之后将其置于0,当增量出现时,它将继续为无穷大。

也许我误解了计时器是如何工作的,但是在阅读了它和JPanels的文档后,我仍然不明白为什么这样的方法不起作用。更不用说JPanels的负坐标几乎没有。

提前感谢您的所有解释!

编辑(27.07.2016)

@camick的回答让它发挥作用,但我仍然没有低于它它,虽然它帮助我缩小了一点问题:

为什么在将位置设置为负值后重新完成布局?是什么导致它重新完成?

1 个答案:

答案 0 :(得分:1)

  

理论上代码是相同的,唯一的区别在于开始位置,结束位置和增量

实际上它不一样。

您可以使用面板的可见性进行游戏,逻辑会根据您单击的按钮而有所不同。我猜测setVisible(true)语句正在调用正在重置组件位置的布局管理器。

无需更改面板的可见性。摆脱setVisible(...)两个陈述。

此外,您可能希望保持按钮启用,您可以重复测试滑入/滑出,而无需重新启动程序。

编辑:

  

如果是这种情况,为什么getX()给出-99

因为在执行该语句时尚未完成布局。

代码并不总是按顺序执行。有时,Swing方法将使用SwingUtiltites.invokeLater()在Event Dispatch Thread(EDT)的末尾添加代码。

这很容易验证。只需按如下方式更改代码,即可查看调用布局的时间。

  JPanel panelContainer = new JPanel()
  {
    @Override
    public void doLayout()
    {
        System.out.println("layout");
        super.doLayout();
    }
  };