I am new to swing and designing an interface using java swing. I want a drawer to pull out with sliding animation on a button click. Firstly, is it possible to do so and if yes, how do I do it. Thank you. I will appreciate a response in terms of some specific method information.
问题:
回答1:
There are a number of possible ways you might achieve depending on what you want to achieve.
The basic method would be simply draw the graphics and a Swing Timer
This would allow you to simply update a variable which would act as the bases for the size of the draw, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawerPaneTest {
public static void main(String[] args) {
new DrawerPaneTest();
}
public DrawerPaneTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new DrawerPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawerPane extends JPanel {
private boolean drawIn = false;
private Timer timer;
private int drawWidth = 0;
private int drawDelta = 4;
public DrawerPane() {
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
timer.stop();
drawIn = !drawIn;
drawDelta = drawIn ? 4 : -4;
timer.start();
}
});
timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
drawWidth += drawDelta;
if (drawWidth >= getWidth() / 2) {
drawWidth = getWidth() / 2;
timer.stop();
} else if (drawWidth < 0) {
drawWidth = 0;
timer.stop();
}
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, drawWidth, getHeight());
g2d.dispose();
}
}
}
This is really basic and doesn't take into account things like slow out/slow in concepts. For those, you'd better look at a dedicated animation framework, like
- Timing Framework
- Trident
- Universal Tween Engine
Which you might use depends on what it is you want to achieve, I personally like the Timing Framework, mostly because it gives me a lot of freedom, where as something like Trident has being (mostly) designed to provide the ability to change properties on a object, such as the size or position, for example. While the Timing Framework can do this do, it would require more work to get it that point.
I've not used the Universal Tween Engine, but have seen some real nice examples, such as the Sliding-Layout, which might actually meeet your needs...
回答2:
First of all, I think that you shouldn't use Canvas
, since, IMO, you shouldn't mix Swing's Components with AWT if it's not necessary (I'm talking in terms of the actual components you place in the GUI - I know Swing is built on top of AWT).
You might instead want to use a JPanel
and perform custom painting using its paintComponent
method. There are many tutorials about this (e.g. Lesson: Performing Custom Painting).
Once you figured out how to draw your drawer inside your JPanel
(simply using Graphics2D
drawing), you'll want to animate it: basically, you'll just need to update some of its properties, most likely some position...
Would you like to have some nice easing effects and everything being easily handled and packaged, I would recommend you to have a look to the Universal Tween Engine. I've already used it and could help you with that as well.
Once you have your Universal Tween Engine library linked to your project, simply use some call as following:
Tween
.to(drawerProperties, Type.POSITION, 10.0f) // animate the POSITION property of your drawerProperties on 10.0 units of time
.target(100) // set the number of frames of that animation to
.ease(Quad.OUT) // set a nice quadratic effect on the animation
.start(tweenManager); // launch the animation
Then, elsewhere, you just need to have a Thread
running that constantly updates your TweenManager
using TweenManager#update
.
Once again, it looks like a lot of work but it actually is very easy to use and the Universal Tween Engine's getting started section is extremely good. Moreover, if you want to really add animation to your project, this could definitely be a great tool to use :)
One last point: you might need to update your properties in the Swing's Event Dispatch Thread, depending on how exactly will your solution be implemented. If you don't know so much about that, you could read Lesson: Concurrency in Swing - or just search StackOverflow if you've specific questions :)