[Stripped down versions of code below is here.]
0. Assignment: Please read chapters 13 on graphics and 14 on threads.
1. Graphics
JButton quitButton = new JButton("Quit");
JFrame theFrame = new JFrame("This is my window");
theFrame.getContentPane().add(quitButton);
(From what I've said, you'd get the impression that components and containers
are entirely distinct kinds of animals, but in fact the class hierarchy is
pretty tangled in this area--e.g. javax.swing.JComponent derives from
java.awt.Container... which derives from java.awt.Component)
public void actionPerformed(ActionEvent e);
quitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
// alternatively, with a named inner class:
// class myActionListener implements ActionListener {
// public void actionPerformed(ActionEvent e) { System.exit(0); }
// }
// myActionListener mal = new myActionListener();
// quitButton.addActionListener(mal);
// NoBehavior.java
// need to import the swing package so we can access JFrame etc.
import javax.swing.*;
// subclass JFrame, a fundamental Swing container class
public class NoBehavior extends JFrame {
public NoBehavior() {
// call the constructor in the superclass
super("I am a frame");
// we want to display a menu; there are three components we have to contend with
// here: menubar (of which a container can only have one at a time), menu (of which
// a menubar can have several), menu item (of which a menu can have several); so
// we make instances of the JMenuBar, JMenu, and JMenuItem classes, and then add
// the menu item to the menu, add the menu to the menubar, and point the container
// at its menubar
JMenuBar myMenuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem quitItem = new JMenuItem("Quit");
fileMenu.add(quitItem);
myMenuBar.add(fileMenu);
setJMenuBar(myMenuBar);
// a couple final details to take care of: we say how large the JFrame should be,
// and also that we want it to display
setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
NoBehavior nb = new NoBehavior();
}
}
// Behavior.java
import javax.swing.*;
// now that we're going to be doing some event-handling, we need to import
// java.awt.event
import java.awt.event.*;
// basic structure remains unchanged from the previous example: the class extends
// JFrame; in main() we just make an instance of the class, so all the fun happens
// in the constructor
public class Behavior extends JFrame {
public Behavior() {
super("I am a frame");
// this is a shortcut, introduced in Java 1.3, that lets a program understand
// window close events; in the good old days you had to add a WindowListener
// by hand, using the same kind of syntax we have below for the menu item
setDefaultCloseOperation(EXIT_ON_CLOSE);
JMenuBar myMenuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem quitItem = new JMenuItem("Quit");
// ok, the menu structure is all set up, so now we have to say what to do when
// the "Quit" item is chosen; a menu item gets an ActionEvent when it's
// selected, so we have to create an object implementing the ActionListener
// interface, and pass it to the addActionListener() method of the menu item;
// as in my example in the initial discussion of event-handling above, the
// object is an instance of an "anonymous inner class", and all its
// actionPerformed() method says to do is exit the program immediately
quitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
fileMenu.add(quitItem);
myMenuBar.add(fileMenu);
setJMenuBar(myMenuBar);
setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
Behavior b = new Behavior();
}
}
// MouseReader.java
import javax.swing.*;
// needed for FlowLayout etc.
import java.awt.*;
import java.awt.event.*;
// needed for Date
import java.util.*;
// same basic structure as previously: a JFrame-extending class, all the action
// in the constructor
public class MouseReader extends JFrame {
JButton button;
JTextField tX, tY, tDate;
public MouseReader() {
super("I am a frame");
setDefaultCloseOperation(EXIT_ON_CLOSE);
// to manipulate the JFrame the way we want to here, we're going to need
// (unlike the case of tacking on a menu bar) a reference to its "content
// pane"
Container c = getContentPane();
// the arrangement of components in a container is governed by its
// "layout"; here we say we'd like a "flow" layout, which orders
// components from left to right, row by row
c.setLayout(new FlowLayout());
// make instances of the components
tX = new JTextField(5);
tY = new JTextField(5);
tDate = new JTextField(20);
button = new JButton("The Button");
// add a listener to the button to listen for mouse motion events;
// the MouseMotionListener interface mandates mouseDragged() and
// mouseMoved() methods, the former of which we just ignore;
// mouseMoved() fetches the mouse's x and y coordinates and the
// event time from the event object, and writes them into the text
// fields, using the setText() method of JTextField
button.addMouseMotionListener(new MouseMotionListener() {
public void mouseDragged(MouseEvent e) { }
public void mouseMoved(MouseEvent e) {
// call getX() on "the event" to get the mouse's x coordinate
// (as an int); setText() wants a String parameter, so we turn the
// int into an Integer, and call Integer's toString()
tX.setText((new Integer(e.getX())).toString());
tY.setText((new Integer(e.getY())).toString());
Date d = new Date(e.getWhen());
tDate.setText(d.toString());
}
});
// add the button and text fields to the container
c.add(tX);
c.add(tY);
c.add(button);
c.add(tDate);
setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
MouseReader b = new MouseReader();
}
}
2. Threads
public void run();In either case, you write a version of run() that contains all you want your thread to do. You start the thread by calling its start() method (inherited from Thread), which does some behind the scenes work to call your run() (this is strange, but no stranger than execution magically beginning at the start of main() in a regular Java application); and the thread then executes 'til run() terminates.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
// overall structure similar to previous examples: our main class extends
// JFrame; main() just makes an instance of the class, all the work's in the
// constructor
public class Counter extends JFrame {
// this is going to be our separate thread for handling the incrementing
// counter
private SeparateSubTask sp = null;
// text field and buttons
private JTextField t = new JTextField(10);
private JButton
start = new JButton("Start"),
onOff = new JButton("Toggle");
// constructor; the operations here follow the same general lines as the
// earlier Swing examples
public Counter() {
// set up for window closing
setDefaultCloseOperation(EXIT_ON_CLOSE);
// get the content pane of the JFrame and set the layout
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
// add the text field to the JFrame
cp.add(t);
// add an ActionListener to the start button that creates an
// instance of our Thread class (if we haven't already done this)
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (sp == null) sp = new SeparateSubTask();
}
});
// add the start button to the JFrame
cp.add(start);
// add an ActionListener to the toggle button that calls a method that
// just toggles a boolean variable
onOff.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (sp != null) sp.invertFlag();
}
});
// add the toggle button to the JFrame
cp.add(onOff);
setSize(300, 100);
setVisible(true);
}
// here's the class definition for the thread
class SeparateSubTask extends Thread {
// state of the counter
private int count = 0;
// are we running or paused?
private boolean runFlag = true;
// constructor for the thread; it just calls start() on itself (i.e.,
// when a thread object of this kind is created, it starts running
// automatically
SeparateSubTask() { start(); }
void invertFlag() { runFlag = !runFlag; }
public void run() {
// run() runs forever
while (true) {
// sleep() is a Thread method that'll make the thread it's called
// on unrunnable for the specified number of milliseconds; sleep()
// can throw an exception, so we wrap the call in a try-catch
try { sleep(100); }
catch (InterruptedException e) { System.out.println("Oops"); }
// (depending on whether we're paused or running), increment the
// counter and write its value into the text field
if (runFlag)
t.setText(Integer.toString(count++));
}
}
}
public static void main(String[] args) {
Counter c = new Counter();
}
}
// as currently commented, this program will probably produce reasonable-looking
// results; uncomment the for-loop in incrementCounter() and all hell breaks
// loose; switch to the "synchronized" signature for incrementCounter() and order
// is restored
public class ThreadTest {
private static int counter = 0;
// constructor; make some threads and start them
public ThreadTest() {
final int numThreads = 25;
for (int i = 0; i < numThreads; i++)
(new InternalThread(i)).start();
}
// public synchronized void incrementCounter() {
public void incrementCounter() {
int tmp = counter;
// throw some sand in there (and hope for thread pre-emption); there are other
// ways to do this: one would be to put the thread to sleep()
// for (int i = 0; i < 10000000; i++) ;
tmp = tmp + 1;
counter = tmp;
}
// er, getCounter() causes additional complications--incrementCounter and
// getCounter() together aren't atomic, so it'd really be better to
// get rid of this
public int getCounter() { return counter; }
// the thread class; 'threadNum' is just for identification purposes in the
// print statement
class InternalThread extends Thread {
private int threadNum;
public InternalThread(int k) { threadNum = k; }
// a nice simple run(): call incrementCounter() in the enclosing object,
// and then print some stuff
public void run() {
incrementCounter();
System.out.println("Thread " + threadNum + ": " + getCounter());
}
}
public static void main(String[] argv) {
ThreadTest t = new ThreadTest();
}
}
3. "Reflection"
// lots and lots of stuff snipped to save space
package dom;
public class Counter {
// here's the name of the parser we'll use by default
protected static final String DEFAULT_PARSER_NAME = "dom.wrappers.Xerces";
public static void main(String argv[]) {
ParserWrapper parser = null;
// deal with command line args
for (int i = 0; i < argv.length; i++) {
String arg = argv[i];
if (arg.startsWith("-") { // we want options to start with a hyphen
String option = arg.substring(1);
if (option.equals("p")) { // is this the p-is-for-parser option?
String parserName = argv[++i];
try {
// Here's the fun part. The program only learns the name of the
// class the user wants to user for the parser now, at runtime.
// Call Class.forName() on the string we get from the command line
// to get a Class object; call newInstance() on that object to
// make a new object of that class; cast to something convenient
parser = (ParserWrapper)Class.forName(parserName).newInstance();
}
catch (Exception e) { System.out.println("Oops"); }
}
// do other options
}
}
if (parser == null) {
try {
parser = (ParserWrapper)Class.forName(DEFAULT_PARSER_NAME).newInstance();
}
catch (Exception e) { System.out.println("Oops"); }
}
// now we've got our parser, proceed with the program