I am writing the code of showing images in Jframe in certain directory. The Jframe will show image one at a time.
My code showing that jframe's size changing but the image doesn't change.
I put revalidate and paint but the images are not refreshed.
Here is updateFrame function which has logic of updating.
private void updateFrame(JFrame f, String billBoardImageFileLocation, int imageNumber) throws ClassNotFoundException, IOException {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); //this is your screen size
File folder = new File(billBoardImageFileLocation);
String[] extensions = new String[]{"jpeg", "jpg"};
List<File> imageFiles = (List<File>) FileUtils.listFiles(folder, extensions, false);
ImageIcon image = new ImageIcon(ImageIO.read(imageFiles.get(imageNumber % imageFiles.size()))); //imports the image
if (isDebug.equals("Y")) {
System.out.println("Files:" + imageFiles.get(imageNumber % imageFiles.size()).getAbsolutePath());
}
JLabel lbl = new JLabel(image); //puts the image into a jlabel\
f.getContentPane().add(lbl); //puts label inside the jframe
f.setSize(image.getIconWidth(), image.getIconHeight()); //gets h and w of image and sets jframe to the size
f.getContentPane().revalidate();
int x = (screenSize.width - f.getSize().width) / 2; //These two lines are the dimensions
int y = (screenSize.height - f.getSize().height) / 2; //of the center of the screen
f.setLocation(x, y); //sets the location of the jframe
f.setVisible(true); //makes the jframe visible
f.revalidate(); // **** added ****
f.repaint();
f.getContentPane().revalidate();
f.getContentPane().repaint();
}
This is how I invoke the updateFrame function.
try
{
pProcess = pb.start();
if (showBillBoard.toUpperCase().equals("Y")) {
ProcMon proMon = new ProcMon(pProcess);
Thread t = new Thread(proMon);
t.start();
JFrame f = new JFrame(); //creates jframe f
if (isDebug.equals("Y")) {
System.out.println("Starting Thread");
}
int imageNumber = 0;
while (!proMon.isComplete()) {
updateFrame(f, billBoardImageFileLocation, imageNumber);
Thread.sleep(Integer.parseInt(billBoardImageUpdateInterval)*1000);
if (isDebug.equals("Y")) {
System.out.println("Updating Framework");
}
imageNumber++;
}
f.dispose();
}
}
JLabel lbl = new JLabel(image);
Don't create a new label, just update the icon of the existing label:
label.setIcon( image );
So change the method parameters to pass in the label as well as the frame.
That's all you need to do.
You're doing long-running code on the Swing event thread, freezing it. Solution: don't. Swap your images using a Swing Timer, as this will allow repeated actions that don't step on the Swing event thread. Also never call Thread.sleep on this thread. For more on the EDT, the Swing event dispatch thread, please read Concurrency in Swing.
Related
I'm writing a little photo application (asked some questions before) and I have one problem which I cannot resolve. The idea is that there are two sections: the upper one is for an overview (using thumbnails) and the lower one shows the selected image in it's full size. I cannot use ImageIO (required by my lecturer).
I'm using a JList for the overview but most images are not visible. I chose a folder with about 20 images and only 2 show up. And one of them isn't even centered.
For some reason, if I delete those lines:
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
One image shows up that wasn't visible before, but now the other two disappear.
This is my code:
public class PVE extends JFrame {
private JFileChooser fileChoose;
//MenuBar
private JMenuBar menubar;
private JMenu file;
private JMenuItem openFolder;
private JMenuItem exit;
//Thumbnails
private JList thumbnaillist;
private DefaultListModel<ImageIcon> listmodel;
private JScrollPane tscroll;
private ImageIcon thumbs;
private int thumbW = 100;
private int thumbH = 100;
//for full size view
private JPanel imgview;
public PVE() {
setLayout(new BorderLayout());
//MenuBar
menubar = new JMenuBar();
file = new JMenu("File");
openFolder = new JMenuItem("Open folder...");
exit = new JMenuItem("Quit");
file.add(openFolder);
file.addSeparator();
file.add(exit);
menubar.add(file);
setJMenuBar(menubar);
fileChoose = new JFileChooser();
openFolder.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
fileChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChoose.showOpenDialog(null);
File chosenDir = fileChoose.getSelectedFile();
loadToThumbView(chosenDir);
}
});
//Thumbnail view
listmodel = new DefaultListModel();
thumbnaillist = new JList(listmodel);
thumbnaillist.setLayoutOrientation(JList.HORIZONTAL_WRAP);
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
thumbnaillist.setVisibleRowCount(1);
tscroll = new JScrollPane(thumbnaillist, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tscroll.setPreferredSize(new Dimension(0, 100));
add(tscroll, "North");
//for full size view
imgview = new JPanel();
imgview.setBackground(Color.decode("#f7f7f7"));
add(imgview, "Center");
setTitle("Photo Viewer");
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
}
setSize(700, 700);
setLocation(200, 200);
setVisible(true);
}
public void loadToThumbView(File folder) {
listmodel.removeAllElements();
File[] imgpaths = folder.listFiles();
for (int j = 0; j < imgpaths.length; j++) {
listmodel.addElement(resizeToThumbnail(new ImageIcon(imgpaths[j].toString())));
}
}
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bf.createGraphics();
g.drawImage(img, 0, 0, thumbW, thumbH, null);
ImageIcon kB = new ImageIcon(bf);
return kB;
}
public static void main(String argv[]) {
PVE pv = new PVE();
}
}
Your problem is because of the way you're scaling your images.
I'm not exactly sure why but I guess it has something to do with the BufferedImage#createGraphics() call and that I was able to reproduce the problem with .jpg images while .png files were correctly painted.
However if you scale your images instead of converting them to a BufferedImage and getting a new ImageIcon from it, you get the correct output:
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
Image scaled = img.getScaledInstance(thumbW, thumbH, Image.SCALE_SMOOTH);
return new ImageIcon(scaled);
}
This is the folder I used to test:
And the outputs with your code and mine:
Important notes
And as as a recommendation don't make a window that big if all you're using is that little bar above. If you're adding something else below, then it's ok but for now it's not that "user friendly" (IMHO). Instead of JFrame#setSize() you could try using JFrame#pack() method so your frame resizes to it's preferred size.
Some other things I noted in your program:
You're not placing it inside the Event Dispatch Thread (EDT) which is dangerous since your application won't be Thread safe that way. You can change that if you change your main method as follows:
public static void main(String argS[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PVE pv = new PVE();
}
});
}
You're setting the JScrollPane preferred size, instead you should override its getPreferredSize() method, see Should I avoid the use of setPreferred|Maximum|MinimumSize methods in Java Swing? (YES)
You're extending JFrame, you should instead create an instance of it unless you're overriding one of its methods (and you're not, so don't do it) or you have any good reason to do it. If you need to extend a Container you should extend JPanel instead, as JFrame is a rigid container which cannot be placed inside another one. See this question and this one.
I think I'm not missing anything, and hope this helps
Your “scaled” images are actually images which are the same size as the original image, but are blank except for a scaled version drawn in the upper left corner. That upper left corner is clipped out of view in each rendered cell (at least for the somewhat large images I tested with).
The scaled image needs to be created with the thumbnail size, not the size of the original image. Meaning, change this:
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
to this:
BufferedImage bf = new BufferedImage(thumbW, thumbH, BufferedImage.TYPE_INT_ARGB);
I want to make a Swing version TimeBomber, which means when time is counted down to 1 the Bomb will blow up! I have two images, images.png for a bomb in normal state, bomber.jpg for a bomb that has blown up. Apparently I need to change the images.png(which is already in an JLabel) to bomber.jpg when i==1; But I have no idea of how to change the pic location content in ImageIcon and as the change happens in anonymous inner class, so change value became difficult as final type var is not modifiable unless you call function.
public class TimeBomber {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
//create Jframe
JFrame app = new JFrame("Time Bomber");
//create JPanel
final JPanel panel = new JPanel();
//JLabel with first Picture
JLabel pic = new JLabel(new ImageIcon("images.png"));
pic.setSize(100, 100);
//Label for displaying time digit
final JLabel label = new JLabel("");
label.setLocation(200, 250);
//create another thread
Thread time = new Thread(){
public void run(){
for(int i=10; i>0; i--){
if(i==1){
JLabel picSecond = new JLabel(new ImageIcon("Bomber.jpg"));
//<--Fact is I dont want to create another JLabel, I want to modify the pic location content in JLabel pic.
picSecond.setSize(100, 100);
panel.add(picSecond);
}
label.setText("Time: "+i);
try {
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
//add every component to where it belongs
panel.add(pic);
panel.add(label);
app.add(panel);
app.setSize(300, 400);
app.setVisible(true);
app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
time.start();
}
}
Wrap the code in SwingUtilities.invokeAndWait() (or SwingUtilities.invokeLater())
if(i==1){
JLabel picSecond = new JLabel(new ImageIcon("Bomber.jpg"));//<--Fact is I dont want to create another JLabel, I want to modify the pic location content in JLabel pic.
picSecond.setSize(100, 100);
panel.add(picSecond);
}
label.setText("Time: "+i);
TO avoid recreation of the JLabel make it the class' field and add to panel just once. Then use picSecond.setIcon() to update the image.
BTW it's better to have kind of images cache to avoid image recreation on each step.
I have a program that does several thing and displays different JFrames after several actions. When I launch the first JFrame from the main, it all goes ok, but When I launch it from another class different from the main class, it doesn't shows up.
What is the point? What am I doing wrong?
Here's some code:
This is called from the main:
SwingUtilities.invokeLater(new Runnable() {
PdfFileUtils pfu = new PdfFileUtils(path);
public void run() {
try {
PdfToImg.setup(pfu, null);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
And it works.
And this is called from another class that is used after some operations:
pfu.setPath(SIGNED);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
PdfToImg.setup(pfu, data);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
Sometimes (every 4 or 5 executions), it launches interrupted exception.
I also tried launching the second frame in this way:
pfu.setPath(SIGNED);
try {
PdfToImg.setup(pfu, data);
} catch (IOException ex) {
ex.printStackTrace();
}
But it shows up for a second and than disappears.
EDIT :
This is the setup() method:
public static void setup(PdfFileUtils pfu, BiometricData data) throws IOException {
// load a pdf from a byte buffer
File file = new File(pfu.getPath());
RandomAccessFile raf = new RandomAccessFile(file, "r");
FileChannel channel = raf.getChannel();
ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0,
channel.size());
PDFFile pdffile = new PDFFile(buf);
int numPgs = pdffile.getNumPages();
ImageIcon[] images = new ImageIcon[numPgs];
for (int i = 0; i < numPgs; i++) {
// draw the first page to an image
PDFPage page = pdffile.getPage(i + 1);
// get the width and height for the doc at the default zoom
Rectangle rect = new Rectangle(0, 0, (int) page.getBBox()
.getWidth(), (int) page.getBBox().getHeight());
// generate the image
Image img = page.getImage(rect.width, rect.height, rect, null,
true, true);
pfu.setWidth(rect.width);
pfu.setHeight(rect.height);
// save it on an array
images[i] = new ImageIcon(img);
}
if(data != null){
SignedFileDisplay fileDisplay = new SignedFileDisplay(pfu, data);
fileDisplay.DisplayAndSelect(images);
} else{
SignPosition signPos = new SignPosition(pfu);
signPos.DisplayAndSelect(images);
}
raf.close();
}
The JFrames are launched by SignedFileDisplay(pfu, data) and by SignPosition(pfu). They work both if launched by the main, and no one the second time.
The constructors are:
public SignPosition(PdfFileUtils pfutils) {
pfu = pfutils;
// scale dimensions
width = (int) (scale * pfu.getWidth());
height = (int) (scale * pfu.getHeight());
// sets the frame appearance
sp.setSize(width + 8, height + 68);
sp.setVisible(true);
sp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sp.setLocationRelativeTo(null);
// Add the image gallery panel
add(imageGallery, BorderLayout.PAGE_START);
// creates the JButtons objects for each button
JButton FIRST = new JButton("|<<<");
JButton PREVIOUS = new JButton("< Prev");
JButton OK = new JButton("Ok");
JButton NEXT = new JButton("Next >");
JButton LAST = new JButton(">>>|");
// adds the buttons to the button panel
JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout(1, 4));
buttons.add(FIRST);
buttons.add(PREVIOUS);
buttons.add(OK);
buttons.add(NEXT);
buttons.add(LAST);
// add buttons on the bottom of the frame
add(buttons, BorderLayout.SOUTH);
// register listener
FirstButtonListener FirstButton = new FirstButtonListener();
PreviousButtonListener PreviousButton = new PreviousButtonListener();
OkButtonListener OkButton = new OkButtonListener();
NextButtonListener NextButton = new NextButtonListener();
LastButtonListener LastButton = new LastButtonListener();
// add listeners to corresponding componenets
FIRST.addActionListener(FirstButton);
PREVIOUS.addActionListener(PreviousButton);
OK.addActionListener(OkButton);
NEXT.addActionListener(NextButton);
LAST.addActionListener(LastButton);
}
and
public SignedFileDisplay(PdfFileUtils pfutils, BiometricData bd) {
data = bd;
pfu = pfutils;
// scale dimensions
width = (int) (scale * pfu.getWidth());
height = (int) (scale * pfu.getHeight());
// sets the frame appearance
sfd.setSize(width + 8, height + 68);
sfd.setVisible(true);
sfd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sfd.setLocationRelativeTo(null);
// Add the image gallery panel
add(imageGallery, BorderLayout.PAGE_START);
// creates the JButtons objects for each button
JButton FIRST = new JButton("|<<<");
JButton PREVIOUS = new JButton("< Prev");
JButton GRAPH = new JButton("Gaph display");
JButton NEXT = new JButton("Next >");
JButton LAST = new JButton(">>>|");
// adds the buttons to the button panel
JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout(1, 4));
buttons.add(FIRST);
buttons.add(PREVIOUS);
buttons.add(GRAPH);
buttons.add(NEXT);
buttons.add(LAST);
// add buttons on the bottom of the frame
add(buttons, BorderLayout.SOUTH);
// register listener
FirstButtonListener FirstButton = new FirstButtonListener();
PreviousButtonListener PreviousButton = new PreviousButtonListener();
GraphButtonListener GraphButton = new GraphButtonListener();
NextButtonListener NextButton = new NextButtonListener();
LastButtonListener LastButton = new LastButtonListener();
// add listeners to corresponding componenets
FIRST.addActionListener(FirstButton);
PREVIOUS.addActionListener(PreviousButton);
GRAPH.addActionListener(GraphButton);
NEXT.addActionListener(NextButton);
LAST.addActionListener(LastButton);
}
Obviously the both extends JFRAME
Are you typing something into that frame? Do you have any shortcuts defined per application?
I had the same problem with my application frame dissapearing from time to time.
In my case, i had some key shortcuts defined per application and one of them was Shift + C (closing the application - bad choice, i know).. so whenever i wanted to type upper case for "c" into a field, i was actually calling the shortcut to close window.
Have many frames is not a good practice.
You should try to use the JDialog instead of JFrame.
This way you can pass the Main Frame to the others dialogs and let them be modal
Like this:
Opening from main
public class Test extends JDialog {
public Test(Frame frame, String dialogName) {
super(frame, dialogName, true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setBounds(x, y, w, h);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new Test(null, "Test Dialog");
}
}
Opening from another frame
public void yourMethod() {
new Test(yourMainFrame, dialogName);
}
I'm a college student and this is my first time I have ever created a gui in Java. Right now I looked at this answer GUI in Java using Swing and followed the instructions and still nothing happens. Here is the code. I cut out all the irrelevant junk.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Lab4Shell
{
// this holds the current game board
private char[][] gameBoard = new char[7][8];
private JButton[][] gameButtons = new JButton[7][8];
private ImageIcon red = new ImageIcon("Red.jpg");
private ImageIcon black = new ImageIcon("Black.jpg");
private ImageIcon empty = new ImageIcon("Empty.jpg");
private JPanel panel = new JPanel();
private int currentPlayer = 1;
private int numMoves = 0;
//Why do you want everything in constructor?
public Lab4Shell()
{
CreateWindow();
ResetGame();
// set layout
// loop through buttons array creating buttons, registering event handlers and adding buttons to panel
// add panel to frame
// do other initialization of applet
}
public static void CreateWindow()
{
//Sets window title and create window object.
JFrame aWindow = new JFrame("Connect Four");
//Set window position and size
aWindow.setBounds(500,100,400,400);
//What close button does.
aWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Make window visible.
aWindow.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Lab4Shell game = new Lab4Shell();
}
});
}
void ResetGame()
{
JLabel label = new JLabel();
label.setIcon(empty);
for(int r=0;r<gameBoard.length;r++)
{
java.util.Arrays.fill(gameBoard[r],0,gameBoard[r].length,'0');
//loop through board columns
for(int c=0;c<gameBoard[r].length;c++)
{
}
}
// loop through array setting char array back to ' ' and buttons array back to empty pic
// reset currentPlayer and numMoves variables
}
You have to add the created ImageIcons to the panel as Manos said, and being the images at the src folder of Eclipse project, do that:
java.net.URL url = getClass().getResource("red.JPEG");
ImageIcon red = new ImageIcon(url);
If the resources are embedded with the application (within in the jar), the you need to use Class#getResource to load them.
The preferred mechanism for loading images is through the ImageIO API. It supports more image formats (as well as providing a pluggable architecture) and guarantees an image that is ready to be displayed once the read method returns
BufferedImage redImage;
// ...
URL url = getClass().getResource("red.JPEG");
if (url != null) {
redImage = ImageIO.read(url);
} else {
throw new NullPointerException("Unable to locate red image resource");
}
You can try this
BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon( myPicture ));
add( picLabel );
You've never adding anything to your frame - which is causing your problem. So in you createWindow method, you need to call:
aWindow.setContentPane(panel);
Then later on (like in your resetGame method), you'll add your content (like the JLabel) to the panel:
panel.add(empty);
Where it's added to your panel is determined by the LayoutManager of the panel (there are many of them - the default is BorderLayout)
Other helpful things:
Generally, when it makes sense, create/initialize your objects in the constructor and add/remove/update them in the runtime.
For troubleshooting, use the .setOpaque(true) and .setBackground(Color.blue) methods on what you want to see. If you don't see it then, either something is covering it up, or it was never added
Good luck.
I am animating a series of images in java. So far I able to animate without any problem. The problem occur only when I add in control(Start, Stop, etc..). When I press Start in my GUI the GUI does not show the animation only the last frame is shown after the animation has ended.
I not sure is it the threading problem or a painting problem, as I have tried a few methods and none of them worked.
Following is my code:
public class SwingAnimation extends JPanel implements ActionListener {
protected JFrame frame;
protected JLabel lblDisplay;
protected JButton BtnStart, BtnStop, BtnPause;
protected JCheckBox chkLoop;
protected Thread th;
public static void main(String[] args) {
SwingAnimation sa = new SwingAnimation();
}
public SwingAnimation() {
frame = new JFrame("Animation");
Panel panel = new Panel();
lblDisplay = new JLabel();
BtnStart = new JButton("Start");
BtnStop = new JButton("Stop");
BtnPause = new JButton("Pause");
chkLoop = new JCheckBox("Loop");
BtnStop.setEnabled(false);
BtnPause.setEnabled(false);
BtnStart.setActionCommand("start");
BtnStop.setActionCommand("stop");
BtnPause.setActionCommand("pause");
panel.add(lblDisplay);
panel.add(BtnStart);
panel.add(BtnPause);
panel.add(BtnStop);
panel.add(chkLoop);
frame.add(panel, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//set the frame in the center of the screen
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
int screen_x = (screensize.width - frame.getWidth()) / 2;
int screen_y = (screensize.height - frame.getHeight()) / 2;
frame.setLocation(screen_x, screen_y);
BtnStart.addActionListener(this);
BtnStop.addActionListener(this);
BtnPause.addActionListener(this);
chkLoop.addActionListener(this);
th = new Thread();
//ImageAnimator();
}
public void ImageAnimator() {
try {
for (int i = 0; i <= 299; i++) {
ImageIcon images = new ImageIcon("C:\\Users\\Desktop\\Images\\Snap" + i + ".jpg");
lblDisplay.setIcon(images);
th.sleep(25);
}
} catch (InterruptedException e) {
}
}
public void actionPerformed(ActionEvent e) {
if ("start".equals(e.getActionCommand())) {
BtnStart.setEnabled(false);
BtnStop.setEnabled(true);
BtnPause.setEnabled(true);
lblDisplay.setVisible(true);
ImageAnimator();
} else if ("stop".equals(e.getActionCommand())) {
BtnStart.setText("Start");
BtnStart.setEnabled(true);
BtnStop.setEnabled(false);
BtnPause.setEnabled(false);
lblDisplay.setVisible(false);
th = null;
} else if ("pause".equals(e.getActionCommand())) {
BtnStart.setText("Resume");
BtnStart.setEnabled(true);
BtnStop.setEnabled(true);
BtnPause.setEnabled(false);
}
}
}
Quick Fix:
Change ImageAnimator() like this:
lblDisplay.setIcon(images);
lblDisplay.paintImmediately(getBounds());
th.sleep(25);
The problem you're having is that setting an icon does not automatically cause Swing to repaint the component onscreen. Calling paintImmediately will do that.
General advice:
Animation in swing is normally done using the Swing Timer. You'll notice at the moment that your UI is unresponsive - once you've started the animation, you won't be able to stop it until its over. That's because all Swing events happen on a single thread - the Event Dispatch Thread. Running a loop with Thread.sleep(...) in the middle ties this thread up, leaving it unavailable to process other input (such as pressing the stop button)
This article helped me immeasurably when I was trying to understand how Swing handles concurrency, and The Swing Trail has lots of advice on using Swing effectively, painting custom components etc.
I'd also plug the demo code on Filthy Rich Clients, I'm working through the book at the moment and it's worth a look.
This Java 2D games tutorial covers several basic animation techniques. Some related example that illustrate the techniques are cited here, and this complete example illustrates stop and start buttons.