java - Swing JDialog 的内容 Pane 在执行幻灯片时未更新

标签 java swing animation jdialog event-dispatch-thread

祝大家有美好的一天。

我想要实现的目标是,按下按钮时从底部滑入,在框架上显示一个对话框(带有键盘,但这超出了这个问题的范围)。

我是swing的初学者,如果问题很明显,请不要责怪。
我提出了一些代码,实现了这一点(有一些缺陷),但是开始位置和结束位置之间的对话框的实际位置不会向用户显示。动画完成时会出现该对话框,但不会显示它。 有人知道为什么不显示吗?

public class TestSliding
extends JFrame {

private static Window kbdOwner;
private static final double kbdHeightRatio = 1d / 4d;
private static final long kbdSlideDurationMs = 3000;

public static Point getKbdLocation() {
  int x = (int) kbdOwner.getBounds().getLocation().getX();
  int y =
    (int) (kbdOwner.getBounds().getLocation().getY() + kbdOwner.getBounds().getSize().getHeight() - getKbdSize()
        .getHeight());

  return new Point(x, y);
}

public static Dimension getKbdSize() {
  int width = (int) kbdOwner.getBounds().getSize().getWidth();
  int height = (int) (width * kbdHeightRatio);

  return new Dimension(width, height);
}

public static void main(String[] args) {
  SwingUtilities.invokeLater(new Runnable() {

    @Override
    public void run() {
      new TestSliding().setVisible(true);
    }
  });
}

private JButton toogleBtn = new JButton("Toogle");
private VirtualKeyboardSlide slide;

public TestSliding() {
  super();
  kbdOwner = this;
  setTitle("Test Sliding");
  setDefaultCloseOperation(EXIT_ON_CLOSE);
  setLayout(new BorderLayout());
  setBackground(Color.BLUE);

  setResizable(false);
  setSize(1024, 768);

  toogleBtn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent argE) {
      switch (getSlide().getState()) {
        case OUT: {
          getSlide().in();
          break;
        }

        case IN: {
          getSlide().out();
          break;
        }
      }
    }
  });

  JPanel panel = new JPanel();
  getContentPane().add(panel);
  panel.add(toogleBtn);
}

public VirtualKeyboardSlide getSlide() {
  if (slide == null) {
    slide = new VirtualKeyboardSlide();
    slide.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    slide.pack();
    slide.setSize(getKbdSize());
    slide.setLocation(getKbdLocation());
    slide.setVisible(true);
  }

  return slide;
}

public interface IVirtualKeyboardPane {
  public void in();
  public void out();
}

public class VirtualKeyboardSlide
....
// see below
....

public class VirtualKeyboardPane
....
// see below
....

}

对话框:

private class VirtualKeyboardSlide
  extends JDialog {

private static final long serialVersionUID = 1L;

private KeyboardState kbdState_ = OUT;

private double height;
private double width;

/**
 * Constructs a <code>VirtualKeyboardDialog</code>.
 */
public VirtualKeyboardSlide() {
  this(new VirtualKeyboardPane());
}

public <T extends Container & IVirtualKeyboardPane> VirtualKeyboardSlide(T contentPane) {
  super(kbdOwner, ModalityType.MODELESS);
  setContentPane(contentPane);
  setUndecorated(true);
  setState(OUT);
  setBackground(new Color(0, 0, 0, 0));
}

/**
 * Returns the state of the keyboard
 * @return the state of the keyboard
 */
public synchronized KeyboardState getState() {
  return kbdState_;
}

public void in() {
  if (canSlideIn()) {
    setState(SLIDING_IN);

    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        getVirtualKeyboardPane().in();
        setState(IN);
      }
    });
  }
}

public void out() {
  if (canSlideOut()) {
    setState(SLIDING_OUT);

    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        getVirtualKeyboardPane().out();
        setState(OUT);
      }
    });
  }
}

/**
 * Sets the keyboard state
 * @param argState
 */
public synchronized void setState(KeyboardState argState) {
  kbdState_ = argState;
}

/**
 * Returns true if the keyboard can slide in now
 * @return true if the keyboard can slide in now
 */
protected boolean canSlideIn() {
  if (!getState().equals(OUT)) {
    return false;
  }

  return true;
}

/**
 * Returns true if the keyboard can slide out now
 * @return true if the keyboard can slide out now
 */
protected boolean canSlideOut() {
  if (!getState().equals(IN)) {
    return false;
  }

  return true;
}

protected IVirtualKeyboardPane getVirtualKeyboardPane() {
  return (IVirtualKeyboardPane) getContentPane();
}

}

KeyboardState 是一个定义键盘状态的枚举:

public enum KeyboardState {
  SLIDING_IN, SLIDING_OUT, IN, OUT, DIED
}

对话框的内容 Pane 由以下类表示:

public class VirtualKeyboardPane
  extends JPanel
  implements IVirtualKeyboardPane {

private static final long serialVersionUID = 1L;

private int height_;
private int width_;

private int normalHeight_;
private int normalWidth_;

private int x_;
private int y_;

public VirtualKeyboardPane() {
  super();
  setFocusable(false);
  setOpaque(false);
  setBorder(BorderFactory.createEmptyBorder());
}

/** {@inheritDoc} */
@Override
public void in() {
  normalHeight_ = (int) getKbdSize().getHeight();
  normalWidth_ = (int) getKbdSize().getWidth();
  width_ = normalWidth_;
  x_ = 0;
  y_ = 0;

  long currentTime = System.currentTimeMillis();
  long startTime = currentTime;
  long endTime = currentTime + kbdSlideDurationMs;

  height_ = 0;
  while (currentTime < endTime) {
    long elapsedTime = currentTime - startTime;
    float f = ((float) elapsedTime / (float) kbdSlideDurationMs);

    height_ = (int) (f * normalHeight_);

    y_ = normalHeight_ - height_;

    repaint();
    currentTime = System.currentTimeMillis();
  }
}

/** {@inheritDoc} */
@Override
public void out() {
  normalHeight_ = (int) getKbdSize().getHeight();
  normalWidth_ = (int) getKbdSize().getWidth();
  width_ = normalWidth_;
  x_ = 0;
  y_ = normalHeight_;

  long currentTime = System.currentTimeMillis();
  long startTime = currentTime;
  long endTime = currentTime + kbdSlideDurationMs;

  height_ = normalHeight_;
  while (currentTime < endTime) {
    long elapsedTime = currentTime - startTime;
    float f = ((float) elapsedTime / (float) kbdSlideDurationMs);

    height_ = normalHeight_ - (int) (f * normalHeight_);

    y_ = normalHeight_ - height_;

    repaint();
    currentTime = System.currentTimeMillis();
  }
}

@Override
protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  g.setColor(new Color(RGBToFloat(255), RGBToFloat(255), RGBToFloat(255), 0.5f));
  // g.fillRect((int) x_, (int) y_, (int) width_, (int) height_);
  g.fillRect(x_, y_, width_, height_);
}

private float RGBToFloat(int rgbValue) {
  return (rgbValue - 0.5f) / 255f;
}
}

最佳答案

问题是您的方法 in()out() 正在 EDT 上运行,并且会阻塞它直到它们结束,这会阻止 Repaint 事件的调度并显示修改后的键盘位置。

使用 Swing 计时器来调整动画的节奏。这将允许中间重绘实际发生。

关于java - Swing JDialog 的内容 Pane 在执行幻灯片时未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12712900/

相关文章:

java - 如何确定java Web应用程序中资源的路径

javascript - 动画 HTML Canvas 元素

jquery - 允许我的动画出现 "visible overflow"

android - 与 getChildFragmentManager() 的共享转换不起作用但与 getFragmentManager() 一起工作

java - 如何使用 Tomcat 8.0 从 WSDL 生成 Java 客户端? WSDL 文件有多个 xsd 导入

java - 如何在 android 中启用/禁用按钮对象的可绘制对象?

java - 询问 "Update Dependencies from package.json"的对话框提供了 "Run ' npm install'"按钮,*之后* 我已经成功运行我的 Vaadin 14.0.8 应用程序

java - 获取 JFileChooser 中所选文件的大小和名称?

java - JMenuBar 未出现在 JFrame 中

java - 在运行时更改 JList 行颜色