Today we'll look at how to get some more interesting graphics into our applications. First, a couple of basics:
We can't put images on frames, and lay them out with layout managers, etc. They aren't components. Images need a component to 'sit' on. We can lay components out.
frame.add(image); BAD
frame.add(someComponent); GOOD
A very flexible component that we've already seen can render text and HTML, is JLabel. A JLabel can have an Icon, and an Icon can be an Image (ImageIcon in Java).
Creating a JLabel with an image on it is really really difficult:
JLabel label=new JLabel(new ImageIcon("filename.jpg"));
Whew. Now if we add that to a frame, using frame.add(label);, we have an image on our frame. That's fine if we want, say, a button then an image, then a textfield, then an image, etc., but it doesn't help if we want to make the image be the background image for the frame. This does:
frame.setContentPane(label);
Make sure you don't do both, i.e., add the label to the frame, AND set it to be the content pane. I don't know what will happen, but it probably won't do what you expect. That would, due to some implementation details, make the label its own parent, which is only possible on Jerry Springer.
Make sure you set the content pane before you set the layout manager for the frame, and before you start adding components to the frame. If you see nothing, check that you have followed the rules above.
A BoxLayout will work for this, but PercentLayout might look a little better. PercentLayout is a layout manager I wrote, and I use it a lot, but you don't need to. GridBagLayout, TableLayout, HTMLLayout, and others might be more useful to you.
JPasswordField is almost identical to JTextField, except you use getPassword() instead of getText(), but you can still use setText, oddly.
Creating a button with an icon on it is cunningly similar to creating a label with an icon on it.
We can create our own images too, we don't have to always load them from file. Java has a class called BufferedImage, which provides an off-screen place to draw stuff to.
To draw to a BufferedImage, we use image.getGraphics() to get a Graphics
object, and then set colours, draw lines, draw circles, fill ovals, etc.
The Graphics class, and its sister, Graphics2D, provide a lot of functionality that we can use to generate pretty much any image.
import java.awt.FlowLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
class Main
{
public static void main(String[] args)
{
JFrame frame=new JFrame();
frame.setLayout(new FlowLayout());
BufferedImage image=new BufferedImage(400,400,BufferedImage.TYPE_INT_ARGB);
Graphics graphics=image.getGraphics();
graphics.setColor(Color.black);
graphics.drawLine(100,100,200,200);
graphics.setColor(Color.red);
graphics.fillRect(50,30,20,100);
graphics.setColor(Color.pink);
graphics.drawOval(80,20,60,30);
graphics.setColor(new Color(40,100,200));
for (int a=0;a<20;a++)
graphics.drawLine(a*10,40,a*11,120);
graphics.dispose();
JLabel label=new JLabel(new ImageIcon(image));
frame.add(label);
frame.setSize(600,400);
frame.setVisible(true);
}
}
Make your own 'abstract art' with this. 'for' loops are particularly useful in this. If you can't remember those from C (and you can't understand mine above), see the Java Tutorial or this tiny snippet.
First, we'll just make the image change whenever the user clicks on a button. You'll need these lines of code:
JButton button=new JButton("Change something");
button.addActionListener(new ChangeButtonListener(image,frame));
frame.add(button);
And in ANOTHER file:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
public class ChangeButtonListener implements ActionListener
{
BufferedImage image;
JFrame frame;
public ChangeButtonListener(BufferedImage image,JFrame frame)
{
this.image=image;
this.frame=frame;
}
public void actionPerformed(ActionEvent event)
{
Random random=new Random();
int randomX=random.nextInt(400);
int randomY=random.nextInt(400);
int randomX2=random.nextInt(400);
int randomY2=random.nextInt(400);
Graphics graphics=image.getGraphics();
graphics.setColor(Color.green);
graphics.drawLine(randomX,randomY,randomX2,randomY2);
graphics.dispose();
frame.repaint();
}
}
To actually make this animate, you'll want to use a Timer. Java has java.util.Timer and javax.swing.Timer. The Swing timer is the one we want, although they are similar to each other.