Graphics I - University College Dublin

Download Report

Transcript Graphics I - University College Dublin

Simple user interfaces
Liang, Chapter 10 (some parts)
Liang Chapter 11 (some parts)
Jframes : user interfaces
Next we’re going to learn how to get java to create more
complicated JFrames for input and output. These can contain
larger text areas, multiple buttons, choice buttons, graphics, etc.
These are a type of GUI (Graphical User Interface).
In describing Jframes I’m going to use sections of Liang chapter
10 and chapter 11. I’ll skip bits of these chapters, though.
Parts of a JFrame
This is a Jframe. It is a
window with various user
interface components.
Test frame
Every JFrame contains a
contentPane, which is a
Container holding all of the
contents of the JFrame
_ _
The contentPane can
hold JComponents
such as JMenu,
JTextArea,
JCheckBox,
JRadioButton,
JButton etc..
This is a text area
with multiple lines
in it
submit
clear
male
A Jpanel containing two JButtons
and two JCheckBoxs
female
The contentPane
may contain JPanels,
with each panel
containing a subgroup of
JComponents.
Example Jframe (see Liang 10.3.1)
import javax.swing.*; // JFrame is a swing class
public class MyFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my first JFrame");
frame.setSize(400,300); // size of frame in pixels
frame.setVisible(true);
// make the frame appear
// on the screen
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
There’s no System.exit() here. Instead, this line tells the MyFrame
program to exit when the frame window is closed by the user. You just have to
include this to get the program to end properly.
This program does nothing but display an empty Jframe.
Screen coordinates go from upper
left corner.
X
(0,0)
(600,0)
Y
(0,400)
(600,400)
Placing a JFrame at a location
import javax.swing.*;
// JFrame is a swing class
public class MyFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my first JFrame");
frame.setSize(400,300);
// size of frame in pixels
frame.setLocation(300,300); // location of upper-left corner
// of frame on screen (in pixels)
frame.setVisible(true);
// make the frame appear
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Liang 10.3.1 gives code for getting the size of the screen and using
setLocation to place the frame in the center of the screen.
(Click here to download this program)
JFrame with a component (10.3.3)
To add an interface component to a frame (like a JRadioButton, a JButton, a
JTextArea,etc), we have to get the ContentPane of the frame and add the
component to that ContentPane.
A ContentPane is a Container. We can add a component using the
Container class, like this:
Jbutton myButton = new JButton("hello!");
Container content = frame.getContentPane();
content.add(myButton);
Or, more compressed:
Container content = frame.getContentPane();
content.add(new JButton("hello!"));
Or even more compressed:
frame.getContentPane().add(new JButton.("hello!"));
Container is a class from the package java.awt.*. We have to import
java.awt.* to use Container .
JFrame with a component (10.3.3)
import javax.swing.*; // JFrame is a swing class
import java.awt.*;
// awt to use the Container class
// it’s ‘java’ not ‘javax’!
public class MyFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my first JFrame");
frame.setSize(400,300);
Container content = frame.getContentPane();
content.add(new JButton("hello!"));
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
This creates a frame with a single big button in it, saying “hello!”
A JCheckBox component (download here)
import javax.swing.*; // JFrame is a swing class
import java.awt.*;
// to use the Container class
// it’s ‘java’ not ‘javax’!
public class MyJCheckBoxFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my JCheckBox JFrame");
frame.setSize(400,300);
Container content = frame.getContentPane();
content.add(new JCheckBox("check this", true));
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.
}
}
EXIT_ON_CLOSE);
“new JCheckBox(“check this”, true));” creates a JCheckBox with
the box already checked (that’s what the ‘true’ means)
A JTextArea component (liang 11.6)
import javax.swing.*; // JFrame is a swing class
import java.awt.*;
// to use the Container class
// it’s ‘java’ not ‘javax’!
public class MyJTextAreaFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my JTextArea JFrame");
frame.setSize(400,300);
Container content = frame.getContentPane();
content.add(new JTextArea(4,25));
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.
EXIT_ON_CLOSE);
}
}
“new JTextArea(4,25));” creates a JTextArea object that is 4
characters (or lines) high and 25 characters across (for the user to type in).
More than one component in a JFrame.
• The programs we’ve seen so far just put one component into a
JFrame. We usually want more than one component.
• If we have more than one component in a JFrame, we have to
organise their layout.
• We set a layout manager object for the contentPane.
• There are different predefined layout managers:
– flowLayout()
places components left to right in the order they were added
– gridLayout(int rows, int columns) defines a grid of rows*columns locations
– borderLayout() has five locations, north south east west center. This is the
default layout manager in contentPane objects.
• When we add multiple components to the contentPane, they are
placed in position by the layout manager we have placed in the
contentPane. If we put different layout manager objects in, we
will get different layouts.
Creating and setting a LayoutManager
import javax.swing.*;
import java.awt.*;
public class MyFlowFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my flowLayout JFrame");
frame.setSize(400,300);
Container content = frame.getContentPane();
content.setLayout(new FlowLayout());
for(int i=0; i<20; i++){
content.add(new JCheckBox("check " + i));
}
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
} We could use new flowLayout(5,5) , which would put 5 pixel spaces between
components, new flowLayout(FlowLayout.LEFT) which would align
components to the left, or new flowLayout(FlowLayout.LEFT,5,5) to do both
Setting a gridLayout manager (download here)
import javax.swing.*;
import java.awt.*;
public class MyGridFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my gridLayout JFrame");
frame.setSize(400,300);
Container content = frame.getContentPane();
content.setLayout(new GridLayout(10,2));
for(int i=0; i<20; i++){
content.add(new JCheckBox("check " + i));
}
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
} new GridLayout(10,2)creates a layout manager object that puts components in a
grid 10 rows down, 2 columns across. We could use new GridLayout(10,2,5,5),
which would create a 10 by 2 grid with 5 pixel spaces between components
Playing with LayoutManagers
Notice that things are placed in the layout according to the
order in which they were added to the contentPane.
In these examples, I added things using a loop. This is just for
demonstration purposes!
I also added the same thing each time. Again, this is just for
demonstration: you can add any type of JComponent.
•
•
•
•
•
Experiment with these 3 Layout Managers
For each, observe effects of resizing the window
For each, explore arguments to the constructor
To avoid surprises, always explicitly set a LayoutManager
Expect surprises and trial and error
1 JTextArea and 4 JButtons (download here)
import javax.swing.*;
import java.awt.*;
public class MyFourButtonFrame{
public static void main(String[] args){
JFrame frame = new JFrame("my first JFrame");
frame.setSize(400,300);
Container content = frame.getContentPane();
content.setLayout(new BorderLayout());
content.add(new JTextArea(4,25),BorderLayout.CENTER);
content.add(new JButton("North"), BorderLayout.NORTH);
content.add(new JButton("South"), BorderLayout.SOUTH);
content.add(new JButton("West"), BorderLayout.WEST);
content.add(new JButton("East"), BorderLayout.EAST);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE);
}
A BorderLayout Jframe has 5 specified locations:
}
BorderLayout.CENTER,NORTH,SOUTH EAST WEST
MyGridFrame extends Jframe
(download here)
import javax.swing.*;
import java.awt.*;
class MyGridFrame extends JFrame{
MyGridFrame(){
// constructor
super("my gridLayout JFrame");
// superclass constructor
Container content = this.getContentPane();
content.setLayout(new GridLayout(10,2));
for(int i=0; i<20; i++)
{ content.add(new JCheckBox("check " + i));
}
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class testGridFrame{
public static void main(String[] args) {
MyGridFrame frame = new MyGridFrame(); // make a MyGridFrame
frame.setSize(400,300);
// set the size
frame.setVisible(true);
// make it visible
}
} Notice that the MyGridFrame object has methods setSize and
setVisible: it inherits them from JFrame
Liangs FlowLayout example (page 386)
import javax.swing.*;
import java.awt.*;
public class ShowFlowLayout extends Jframe{
public ShowFlowLayout(){
Container container = getContentFrame();
container.setLayout(new FlowLayout(FlowLayout.LEFT,10,20);
for (int i = 1; i <= 10; i++){
container.add(new Jbutton("Component "+i));
}
}
public static void main(String[] args){
ShowFlowLayout frame = new ShowFlowLayout();
frame.setTitle("show flow layout");
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
frame.setSize(400,300);
frame.setVisible(true);
}
}
In this example, the main method is inside the ShowFlowLayout
class, rather than there being a separate test class.
Class JPanel
• Most interfaces combine several kinds of component:
–
–
–
–
–
–
text boxes
messages
check buttons
clickable buttons
menus
graphics
• Often we want to group some of these together, for
layout reasons.
• Interface components are grouped within JPanels
• JPanel comes from javax.swing
Example using JPanel
This is a Jframe. It is a
window with various user
interface components.
Test frame
Every JFrame contains a
contentPane, which is a
Container holding all of the
contents of the JFrame
_ _
The contentPane
contains JComponents
such as JMenu,
JTextArea,
JCheckBox,
JRadioButton,
JButton etc..
This is a text area
with multiple lines
in it
submit
clear
male
A Jpanel containing two JButtons
and two JCheckBoxs
female
The contentPane
may contain JPanels,
with each panel
containing a subgroup of
JComponents.
import javax.swing.*;
// (download here)
import java.awt.*;
class MyFrame extends JFrame{
MyFrame(){
super("JFrame with button and checkbox panel");
JPanel myPanel = new JPanel();
// create panel
myPanel.setLayout(new GridLayout(0,4));
// set layout of panel
myPanel.add(new JButton("submit"));
// add button to panel
myPanel.add(new JButton("clear"));
// add another button
myPanel.add(new JCheckBox("male", true));
// add checkbox to panel
myPanel.add(new JCheckBox("female", false)); // another checkbox
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
content.add(new JTextArea(16,25),BorderLayout.CENTER);
content.add(myPanel,BorderLayout.SOUTH);
// add panel to frame
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class testMyFrame{
public static void main(String[] args) {
MyFrame frame= new MyFrame();
frame.setSize(300,200);
frame.setVisible(true);
}
In this example, Jframe
has two components: a
JTextArea, and the
JPanel, which itself
contains JButtons
and JCheckBoxes
Putting messages in JPanels (liang 10.6)
The things we’ve put in JPanels so far are interface components like
JButtons and JCheckBoxes. How do those things actually get onto the
screen? Jpanel has a method called
public void paintComponent(Graphics g)
which is called whenever a JPanel object is to be “painted” onto the screen. This
is given a Graphics object g by the Java system, which represents the bit of
screen where the JPanel is to be drawn. Every JPanel paints its interface
components onto the screen using this Graphics object g.
We don’t care what goes on inside the paintComponent method. However, if
we want to put messages, or draw pictures, into our JPanels, we need to override
the paintComponent method (redefine the method so that it draws what we want
onto the screen). We use methods in Graphic object g for this:
g.drawString(“Hello”,x,y); // draws string “hello” at location x, y in the bit of
// screen represented by Graphics object g
Extending JPanel and overriding
paintComponent() to draw a message on a panel
import javax.swing.*;
import java.awt.*;
class MyMessageJPanel extends JPanel{
String message;
// message contents for panel
int xlocation,ylocation;
// message location in panel
MyMessageJPanel(String msg, int x, int y){ // constructor
super();
// call constructor for superclass JPanel first
message = msg;
xlocation = x;
This paintComponent method is called whenever
ylocation = y;
a Jpanel is painted on the screen. We’ve changed it
}
so it draws our message whenever it’s called.
public void paintComponent(Graphics g){ // override paintComponent
super.paintComponent(g);
// first do whatever paintComponent in JPanel always does
g.drawString(message,xlocation,ylocation);
}
// next use the drawString method to draw our message in the JPanel
}
Using our extended JMessagePanel
class MyMessageJFrame extends JFrame{
MyMessageJFrame(){
// constructor for MyMessageJFrame
super("JFrame with MyMessageJPanel");
MyMessageJPanel messagePanel;
messagePanel = new MyMessageJPanel("Hello world!",50,50);
// create a MyMessageJPanel object that
// draws "hello world!" at location 50, 50
Container content = this.getContentPane();
content.setLayout(new BorderLayout(15,15));
content.add(messagePanel,BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class testMyFrame{
// class to test out these classes
public static void main(String[] args) {
MyMessageJFrame frame= new MyMessageJFrame();
frame.setSize(300,300);
frame.setVisible(true);
}
}
When the MyMessageJPanel object is painted on the screen, our overridden
paintComponent method will draw the message we gave to the constructor.
Noticing events: A Button Click
• A JFrame contains a JButton
• To respond when the JButton is clicked, we create an actionListener
object to listen for the action of that JButton being clicked.
• That actionListener object must contain a method called
•
public void ActionPerformed(ActionEvent e)
• The actionListener object registers with the Jbutton.
• Thereafter, whenever the JButton is clicked, it calls the
actionPerformed(ActionEvent e) method in the listener.
• The actionPerformed (ActionEvent e) method does whatever we
want to happen when the button is clicked.
Listener registers
with JButton
count
event e:
Click
myActionListener {
actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(“Button click!”);
}
JOptionPane
}
Button Clicked!
Registering a listener object with a source
(a Jbutton)
JButton myCountButton = new JButton(“count");
myCountListener listener = new myCountListener();
myCountButton.addListener(listener);
This snippet of code creates a JButton object, then creates a
myCountListener object, the registers that listener with that button (adds
the listener object as a listener to the button).
This registration step creates the link between the button and the listener: after
this step, when the button is clicked, the actionPerformed() method in
the listener object will be executed.
Next: putting it all together.
Making the JFrame class
implement ActionListener
• Any class at all can implement ActionListener, if it provides the
actionPerformed() method.
• Its most useful to make the class that draws our windows (our
JFrames) also implement ActionListener, so that objects from that
clss not only draw buttons but can respond to events on those
buttons.
• To do this we change our myButtonJFrame class so that it proves an
actionPerformed() method as well as constructing the JFrame object.
• I’ll call this new class EventButtonJFrame
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
// we need event classes
class EventButtonJFrame extends Jframe implements ActionListener{
JTextArea myTextArea = new JTextArea(6,30),
JButton myCountButton = new JButton("Count");
// make button
JPanel buttonPanel = new JPanel();
EventButtonJFrame (){
super(“myButtonJFrame");
myCountButton.addActionListener(this);
// constructor
// register this class as the listener
// for myCountButton
buttonPanel.setLayout(new GridLayout(4,0));
buttonPanel.add(myCountButton);
// add button to panel
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
content.add(myTextArea,BorderLayout.CENTER);
content.add(buttonPanel, BorderLayout.EAST);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,”Count button clicked!");
}
}
Doing something useful
The actionPerformed method in the previous programs doesn’t really do
anything useful.
To get that method to do something useful, we could, for example, give it access
to the JTextArea object created in our JFrame window.
To do this, we will
1) Make the JTextArea object a generally accessible variable in the
Jframe object. To do this, we put
JTextArea myTextArea = new JTextArea("this is a text area",6,30);
at the top of the EventButtonJFrame class definition.
2) Refer to the text in that JtextArea object in the actionPerformed
method, so that when our count button is clicked, we can return some useful
information.
We can get the text inside the JTextArea object by saying
myTextArea.getText();
(we can change that text by saying something like:
myTextArea.setText(“this is the new text”);
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
Download from here
// we need event classes
class EventButtonJFrame extends JFrame implements ActionListener{
JTextArea myTextArea = new JTextArea("this is a text area",6,30);
JButton myCountButton = new JButton("count");
// create button
JPanel buttonPanel = new JPanel();
EventButtonJFrame (){
super("myButtonJFrame");
myCountButton.addActionListener(this);
// add listener
buttonPanel.setLayout(new GridLayout(4,0));
buttonPanel.add(myCountButton);
// add button
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
content.add(myTextArea,BorderLayout.CENTER);
// add text area
content.add(buttonPanel, BorderLayout.EAST);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, “The number of characters in
JTextArea is "+myTextArea.getText().length() );
}
}
Whenever the count button is clicked, we get a message telling us
how many characters are currently in myTextArea.
// continued…
class testEventButtonJFrame {
public static void main(String[] args) {
EventButtonJFrame frame = new EventButtonJFrame();
frame.setSize(300,200);
frame.setLocation(300,330);
frame.setVisible(true);
}
}
This program will respond to a click on the count button by popping
up a text message telling the user how many characters are currently
entered in the JTextArea of the EventButtonJFrame object.
Note that for this program to compile and run properly, it must be in
a file called testEventButtonJFrame.java. This is because
the class with the main method (the one that will actually run) is the
testEventButtonJFrame class.
A listener with two buttons (download here)
If we want our actionListener to respond to more than 1 button,
we have to change the actionPerformed method so that it checks
which button was source of the current event. We do this as follows:
Declare the two buttons as class-level variables; at top of the class, put:
JButton myCountButton = new JButton("count");
JButton myClearButton = new JButton("clear");
In the constructor for the class, register both buttons with the listener
(and add each button to the JPanel as required):
myCountButton.addActionListener(this);
myClearButton.addActionListener(this);
In the actionPerformed method, check which button was the source of
the current ActionEvent e, and respond accordingly:
if (e.getSource().equals(myCountButton)) {…do whatever}
if (e.getSource().equals(myClearButton)) {…do whatever}
Colors, fonts, and drawing graphics
There are lots of other things we can do with JPanels: change colors, set font
sizes, etc. See Liang 10.7 and 10.5, and example 10.5, for details of these. I’ll leave
them to you to read over.
We have extended JPanel to MyMessageJPanel and used g.drawString()
to draw a string (a message) in the panel.
We can use a similar approach to draw graphics in a panel, using the predefined
graphics methods g.drawline(), g.drawRect(), g.drawOval() and so on. To
use these we extend JPanel to JRectPanel, for example, and in JRectPanel
override paintComponent() as follows:
public void paintComponent(Graphics g){ // override paintComponent
super.paintComponent(g);
// first do whatever paintComponent in JPanel always does
g.drawRect(x,y,width,height);
}
// draw a rectangle at x,y with the given width and height
Using the API
There are a lot of details in the javax.swing and java.awt classes I’ve
discussed here. I haven’t mentioned most of the abilities of these classes.
You should look these classes up in the API:
http://java.sun.com/j2se/ (click on ‘API specifications’ under ‘reference’, and
then pick the edition of J2SE you are using: currently probably 1.4.2).
You should look up
javax.swing
and within that look up the classes JFrame, JPanel, JComponent,
JDialog and see the methods that are listed. In JComponent you will see
subclasses such as JTextField, JTextArea, Jbutton,
JRadioButton, JCheckBox and so on. The API explains all of the abilites
of objects in these classes and how they are used.
Within javax.awt you will find the layout managers and various other useful
classes of objects.
Conclusion
• GUI construction and control is not complicated, but there are loads
of details involved.
• You don’t need to know all these details: my aim has been to give a
general idea of what goes on in GUI construction and in event-driven
programming.
• If you’re interested, you can look up the various classes discussed
here in the Java API:
•
http://java.sun.com/j2se/ (click on ‘API specifications’ under
‘reference’, and then pick the edition of J2SE you are using:
currently probably 1.5.0 ).
•
There are very useful tutorials on JFrame use, event-driven
programming and other aspects of Java programming in the API.