Reputation: 514
Good day to all.
What I'm trying to achieve, is to have a dialog (with a keyboard, but this is out of the scope of this question) appear on a frame by sliding in from the bottom when a button is pressed.
I'm a beginner at swing, please don't blame if the problem is obvious.
I threw up some code, that achieves that (with some imperfections), but the actual positions of the dialog between the start and end positions are not shown to the user. The dialog appears when the animation is done, without showing it.
Anyone knows why aren't they showed?
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
....
}
The dialog :
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();
}
}
The KeyboardState is an enum defining the states of the keyboard:
public enum KeyboardState {
SLIDING_IN, SLIDING_OUT, IN, OUT, DIED
}
The content pane of the dialog is represented by the following class:
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;
}
}
Upvotes: 2
Views: 411
Reputation: 47637
The problem is that your methods in()
and out()
are running on the EDT and are blocking it until they end, which prevents Repaint events from being dispatch and display the modified location of your keyboard.
Use a Swing timer instead to pace your animation. This will allow intermediary repaint to actually occur.
Upvotes: 2