The Java language Safe and Portable

Write once, run anywhere

Use: distributed applications, web pages, games, image processing, frontend

Applet from http://www.sunlabs.com/~shirriff/java/marqueelights.html

Applet from http://www.cs.hope.edu/~dbrown/java/LEDSign/WWW/LED.html
Games

Applet from http://www.magnastar.com/games/gobbler/
Network applications CERN particle experiment feedback:

Applet from http://hpslweb.cern.ch/teletext/java/view110-java.html
Animation
                  Bi-Directional
Bubble Sort        Bubble Sort        Quick Sort
          
Applet from http://www.javasoft.com:80/applets/applets/SortDemo/example1.html
Simulators

Applet from http://www.lookup.com/Homepages/96457/digsim/index.html
Applet from http://www.npac.syr.edu/projects/vishuman/VisibleHuman.html
The Java Language Java is similar to C++, without "sharp edges".
  • No pointers
  • No free
  • No goto
  • Arrays bounds checked
  • No multiple inheritance
Hello world import java.applet.*; import java.awt.*; public class Example1 extends Applet { public void paint(Graphics g) { g.drawString("Hello world",75,100); } };

Source Classes import java.applet.*; public class Class2 extends Applet { public void init() { A a = new A(1); a.printit(); a = new A(); a.printit(); } } class A { int x; A() { x = 42;} A(int v) { x = v; } void printit() { System.out.println("A's value is "+x); } } A's value is 1 A's value is 42

Source Inheritance class A { int x; A(int v) { x = v; } } class B extends A { B(int v) { super(v*2); } } A a = new A(1); B b = new B(2);

Source Interface inheritance Interface: method definitions but no code

Can inherit multiple interfaces public interface Drawable { public void setColor(Color c); } public class C implements ImageObserver, Drawable { } Strings Strings are totally different from C String s1 = "Test"; String s2 = s1 + " string"; if (s2.equals("Test string")) { System.out.println("String is "+ s2 +"length "+s2.length()); } char c = s2.charAt(3); System.out.println(s2.toUpperCase()); int n = Integer.parseInt("123"); System.out.println("n is "+n); Arrays int x[] = new int[20]; x[5] = 42; int y[] = {1,2,3,4,5}; Arrays are bound checked. x[20] = 42; // throws ArrayIndexOutOfBoundsException Multidimensional arrays String z[][] = new String[20][20]; Non-rectangular arrays int t[][] = new int[3][]; t[0] = new int[2]; t[1] = new int[30]; t[2] = new int[100]; t[1][15] = 42; Exceptions Exceptions provide an error handling mechanism try { System.out.println(a/b); } catch (ArithmeticException e) { System.out.println("Had a problem!"); } Exceptions propagate upwards until a catch block gets them

Can throw exceptions:

throw new ArithmeticException();
Can have multiple catch blocks: try { } catch (IOException e) { } catch (ArithmeticException e) { } catch (Exception e) { // most general exception } Methods must specify exceptions they throw public Foo() throws IOException { ... } Multi-threading Threads run in same address space

Useful for long computations, preventing GUI from blocking, updating image in background

Thread example class ThreadExample extends Thread { int count=0; public void run() { while (count<100) { System.out.println("hi "+(count++)); try { sleep((int)(5000*Math.random())); } catch (InterruptedException e) {} } } }; ThreadExample t1 = new ThreadExample(); t1.start(); ThreadExample t2 = new ThreadExample(); t2.start();

Source Compiling and running Example1.java: import java.applet.*; import java.awt.*; public class Example1 extends Applet { public void paint(Graphics g) { g.drawString("Hello world",75,100); } }; example1.html: <applet code="Example1.class" width=200 height=200> </applet>

Compile with "javac Example1.java"

Display with "appletviewer example1.html"

Or view on web page with a browser Standalone application import java.awt.*; class StandaloneDemo extends Frame { public static void main(String args[]) { System.out.println("We have "+args.length+" args"); StandaloneDemo sd = new StandaloneDemo(); sd.start(); } public void start() { resize(200,200); show(); } public void paint(Graphics g) { g.drawString("Hello world",60,100); } } Run with "java StandaloneDemo" Safety

  • Runtime bytecode verifier
  • Null reference checking
  • Array bounds checking
  • Garbage collection
  • Exceptions for faults
  • Access to files, network controlled by runtime environment
Bytecodes Compiled to interpreted architecture neutral stack-based byte codes int m1(int a, int b) { if (a>1) { return a+b; } else { return a/b; } } Method int m1(int,int) 0 iload_1 // push a 1 iconst_1 // push 1 2 if_icmple 9 // if a<=1 goto 9 5 iload_1 // push a 6 iload_2 // push b 7 iadd // add 8 ireturn // return a+b 9 iload_1 10 iload_2 11 idiv 12 ireturn // return a/b Distributed objects
  • Communication framework
  • Compound documents
  • Components
Components

Canvas canvas = new Canvas(); Button button = new Button("A Button"); TextField tf = new TextField("A Textfield"); TextArea ta = new TextArea("TextArea", 5, 20); List list = new List(10, true); Choice choice = new Choice(); CheckboxGroup box = new CheckboxGroup(); Label label = new Label("A Label"); Scrollbar sbar = new Scrollbar();

Source Component Layout Default: FlowLayout public void init() { Button but1 = new Button("button1"); Button but2 = new Button("button2"); ... setLayout(new FlowLayout()); add(but1); add(but2); add(but3); add(but4); add(but5); add(but6); }

Source GridBagLayout GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); setLayout(gbl); gbc.gridwidth = 1; gbc.fill = GridBagConstraints.BOTH; gbl.setConstraints(but1, gbc); add(but1); gbl.setConstraints(but2,gbc); add(but2); gbc.gridwidth=GridBagConstraints.REMAINDER; gbl.setConstraints(but3,gbc); add(but3); gbc.gridwidth=2; gbl.setConstraints(but4,gbc); add(but4); gbc.gridwidth=GridBagConstraints.REMAINDER; gbl.setConstraints(but5,gbc); add(but5); gbl.setConstraints(but6,gbc); add(but6);

Source Nested layout Panel p1 = new Panel(); p1.setLayout(gbl); gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 1; gbc.gridwidth=GridBagConstraints.REMAINDER; gbl.setConstraints(but1,gbc); p1.add(but1); gbl.setConstraints(but2,gbc); p1.add(but2); gbl.setConstraints(but3,gbc); p1.add(but3); Panel p2 = new Panel(); p2.setLayout(gbl); gbl.setConstraints(but4,gbc); p2.add(but4); gbl.setConstraints(but5,gbc); p2.add(but5); setLayout(gbl); gbc.gridwidth=1; gbl.setConstraints(p1,gbc); add(p1); gbc.gridwidth=GridBagConstraints.REMAINDER; gbc.fill = GridBagConstraints.BOTH; gbl.setConstraints(p2,gbc); add(p2);

Source Events Propagated events for mouse, keys, GUI actions, focus. public boolean handleEvent(Event evt) { area.appendText(""+evt+"\n\n"); return true; }

Source Event convenience methods Default handleEvent calls:

  • mouseEnter, mouseExit, mouseMove, mouseDown, mouseDrag, mouseUp
  • keyDown, keyUp
  • gotFocus, lostFocus.
  • action

Return true if you process the event. Mouse events

public class Scribble extends Applet { int lastx, lasty; public boolean mouseDown(Event e, int x, int y) { lastx = x; lasty = y; return true; } public boolean mouseDrag(Event e, int x, int y) { Graphics g = getGraphics(); g.drawLine(lastx,lasty,x,y); lastx = x; lasty = y; return true; } }

Source Buttons Button b1 = new Button("Button 1"); Button b2 = new Button("Button 2"); public void init() { add(b1); add(b2); } public boolean action(Event evt, Object obj) { if (evt.target.equals(b1)) { System.out.println("Button 1 pressed"); return true; } else if (evt.target.equals(b2)) { System.out.println("Button 2 pressed"); return true; } else { return super.action(evt,obj); } }

Source Other buttons Choice ch = new Choice(); Checkbox ckbx = new Checkbox("Test"); CheckboxGroup radio = new CheckboxGroup(); Checkbox r1 = new Checkbox("A",radio,true); Checkbox r2 = new Checkbox("B",radio,false); Checkbox r3 = new Checkbox("C",radio,false); public void init() { ch.addItem("Red"); ch.addItem("Green"); add(ch); add(ckbx); add(r1); add(r2); add(r3); } public boolean action(Event evt, Object obj) { if (evt.target.equals(ch)) { System.out.println("Choice " +ch.getSelectedIndex()+ch.getSelectedItem()); return true; } else if (evt.target.equals(ckbx)) { System.out.println("Checkbox "+ckbx.getState()); return true; } else if (evt.target instanceof Checkbox) { System.out.println("Radio:" + ((Checkbox)evt.target).getLabel()); return true; } else { return super.action(evt,obj); } }

Source Scrollbar Events are SCROLL_LINE_UP, SCROLL_LINE_DOWN, SCROLL_PAGE_UP, SCROLL_PAGE_DOWN, SCROLL_ABSOLUTE

Scrollbar sb = new Scrollbar(Scrollbar.HORIZONTAL,0,10,0,100); Label l = new Label(" "); public boolean handleEvent(Event evt) { if (evt.target.equals(sb)) { if (evt.id==Event.SCROLL_ABSOLUTE) { System.out.println("ABSOLUTE "+evt.arg); } l.setText(""+sb.getValue()); return true; } else { return super.handleEvent(evt); } }

Source List and TextField List l = new List(); TextField tf = new TextField("Default"); public void init() { l.addItem("Red"); l.addItem("Green"); l.addItem("Blue"); add(l); add(tf); } public boolean action(Event evt, Object obj) { if (evt.target.equals(l)) { System.out.println("List " +l.getSelectedIndex()); tf.setText(l.getSelectedItem()); return true; } else if (evt.target.equals(tf)) { System.out.println("Text "+tf.getText()); return true; } else { return super.action(evt,obj); } }

Source Graphics public void paint(Graphics g) { g.setColor(Color.red); g.drawLine(0,0,100,100); g.setColor(Color.green); g.drawOval(50,50,100,20); g.setColor(Color.blue); g.drawArc(150,50,40,20,10,90); int x[] = {110,150,130}; int y[] = {80,20,60}; g.fillPolygon(new Polygon(x,y,3)); g.setFont(new Font("Helvetica",Font.BOLD,24)); g.fillRect(250,0,10,40); g.drawString("String", 300,20); }

Source Double buffering

  • Make an image
  • Write to the image, repaint
  • Paint image to screen
  • Override update to prevent flicker
Image img = null; Graphics img_g = null; public void init() { img = createImage(size().width, size().height); img_g = img.getGraphics(); img_g.setColor(Color.black); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { g.drawImage(img,0,0,this); } public boolean mouseDrag(Event e, int x, int y) { img_g.drawLine(lastx,lasty,x,y); repaint(); ... }

Source Image processing public class BugEyes extends Applet implements ImageObserver { public boolean imageUpdate(Image origimg, int infoflags, int x, int y, int w, int h) { repaint(); return true; } Image img = getImage(getDocumentBase(),"foo.gif"); g.drawImage(img,x,y,this);, int pix[] = new int[width*height]; Image piximg = createImage(new MemoryImageSource(width, height, pix, 0, width));

Source Animation public class Anim1 extends Applet implements Runnable { Thread my_thread = null; Image img; public void init() { img = getImage(getDocumentBase(),"foo.gif"); my_thread = new Thread(this); my_thread.start(); } int x=0,y=0,xdir=2,ydir=3; public void paint(Graphics g) { g.drawImage(img, x,y,null); } public void run() { while (true) { x += xdir; if (x<2 || x>size().width-20) { xdir = -xdir; } y += ydir; if (y<2 || y>size().height-20) { ydir = -ydir; } repaint(); try { my_thread.sleep(20); } catch (InterruptedException e) {} } } }

Source More information

Assignment In the assignment, you modify a simple networked drawing program Running the assignment program

Running the demo program

Standalone

  • Save the HTML file as draw.html and the java file as Draw.java.
  • Compile Draw.java with "javac Draw.java".
  • Run the applet with "appletviewer draw.html".
  • Click on buttons to select drawing modes and draw with the mouse.
  • You should also be able to run the applet by loading draw.html into Netscape.

Networked

The drawing program also has a mode where you can connect multiple drawing applets together. Anything drawn in one applet will appear in all the others. To do this, we use a helper program. This helper program accepts connections on port 4321. Any input on a connection is echoed to all the other connections. Since this is like a simple "chat" program, I call it "chatServer", although we'll be using it to broadcast graphics events rather than text.

  • Save the chatServer program in chatServer.java.
  • Compile it with "javac chatServer.java".
  • Run it with "java chatServer". Note that it runs as a standalone program, not an applet.
  • To see what chatServer does, do "telnet localhost 4321" from a couple windows (or "telnet name-of-host 4321" from a different machine). Note that anything you type into one session is echoed to the rest. Exit telnet with control-] and quit.
  • With chatServer still running, start up a couple drawing applets ("appletviewer draw.html")
  • Connect each applet to chatServer by hitting "return" in the connection window. If the applet is running on a different machine from chatServer, you need to explicitly enter the hostname.
  • Now draw in one applet, and the results should be echoed to the other applets.
  • Kill the chatServer.

The program internals

The program is a drawing applet that lets you draw lines, ovals, text, and colored circles on the screen. In addition, it allows you to connect multiple drawing programs together over the network to provide a collaborative drawing environment.

The program is structured as multiple object-oriented classes:

Draw: this is the top-level class and extends the Java Applet class. This class provides the top-level window and the user interface. The init() method sets things up, and then the class just waits for user-interface events.

DrawingCanvas: this class extends the Java Canvas class. It provides the area in which you draw. It provides a double-buffered drawing area (through backingImg and backingGraphics). Mouse and key events are passed to an object that does the actual drawing. DrawObject: this is the superclass that does most of the work. A DrawObject takes mouse events and draws the appropriate stuff on the DrawingCanvas. In addition, this class provides the remote drawing support. This class is subclassed to provide the different operations: DrawLine, DrawCircle, etc. Each of these classes must implement the mouseDown, mouseUp, mouseDrag, and keyPress methods and do the appropriate thing.

DrawConnection: this class sits around and waits for incoming remote drawing invocations. It extends the Java Thread class, so it runs as a separate thread; otherwise the program would hang while we wait for incoming data.

The user interface

The user interface is defined in Draw. The screen is divided into three parts: a Panel of buttons (buttonpanel) to the left, the DrawingCanvas to the right, and a Panel of option controls on the bottom. The buttonpanel contains buttons for the different drawing modes. The optionpanel contains a Choice to select the color, a Checkbox to select fill mode, a TextField to specify the network connection, and various Labels.

Network connections

To connect multiple drawing applets together, things get a little tricky because of the Java security model. An applet can't listen on random sockets, but a stand-alone application can. So I've made a stand-alone application to do the listening and tie the servers together. Now, what you do is have all the draw programs connect to "chatServer"; each one sends drawing operations to the chatServer and the others all receive these operations. To link up, type the hostname in the "connection" window in the draw window and hit return.

Note: an applet running with appletviewer can connect to any host, but an applet running under Netscape can only connect to the same host that is providing the applet. I.e., if you're loading this page locally and it says "//localhost/...", you have to specify "localhost" as the hostname. If you're getting the pages off foo.bar.edu, you have to run chatServer on foo.bar.edu and specify foo.bar.edu for the hostname. The Assignment

  • The drawing program currently only supports three colors. Add support for additional colors. You will have to do more addItem calls to add the colors to the Choice component. You will also need to update the event handling code to do the right thing when these are selected. Finally, you need to add a setColor call to DrawCircle and DrawText to make color selection work here.
  • Add support to change the size, name ("Helvetica", "TimesRoman", "Courier") and style (Font.PLAIN, Font.BOLD, Font.ITALIC) of text. You can use a Choice or a TextEntry for input, or even a Scrollbar for the size. Checkboxes could select the style. Add fields to Options to hold these. You'll make a new Font(name,style,size) and then do a setFont on the appropriate graphics. Updating the font in the middle of a string will be tricky, since there isn't an easy way to erase the old string, so you can just do the update on a mouseDown.
  • Add the missing functionality to remote operation. In particular: the option code needs to handle more colors and needs to transmit the fill flag. DrawText needs to send the appropriate events. While implementing this, think about remote object invocation in Java and what it lacks. Note that you have to implement remote method invocation yourself; a distributed object model would let you invoke remote objects transparently, without all the fuss of encoding data into a stream.
  • The drawRender class puts a block of pixels on the screen; currently this is just a colored circle. Make the drawRender class do something more interesting; use some of your previous graphics knowledge to render something.
  • Extend the program to draw splines. Make a class DrawSpline that subclasses DrawObject and add a button to activate it. The simplest approach is to collect four mouse clicks and then draw the Bezier spline that uses these points as control points. Hint: define an array of four ints with "int xpts[] = new int[4];" for the x and y control points. You can use graphics.drawLine to draw the line segments.

    Advanced: make the current spline editable. When you get a mouseDown, see if it is close to any of the control points. If so, let the user drag the control point around and redraw the spline dynamically. Note: this gets tricky if you want to avoid messing up the screen. The xor trick won't work well since you're likely to draw some pixels twice. One solution: save the current drawing image before you start displaying the spline. Then, whenever you update the spline, draw the old background and then the spline. Code to do this:

      class DrawSpline extends DrawObject { Image saveImg = null; public DrawSpline(...) { // We get an image buffer of the proper size saveImg = parent.createImage(parent.size().width, parent.size().height); // Tricky bit: we tell Draw to update our image rather than the screen image parent.update(saveImg.getGraphics()); } void drawTheSpline() { graphics.drawImage(saveImg,0,0,null); // redraw what was there before // now render the spline segments with graphics.drawLine(...); } }