JAVA 4

10. AWT

Text, Textfield, and TextArea

1.      (Sect. 10) How can I write text at an angle?

*Check out http://www.nyx.net/~jbuzbee/font.html. Jim has some code to do exactly this. A good way to do it is to draw the text to an offscreen image and write an ImageFilter to rotate the image.

Also, from JDK 1.2 on, the Java 2D API handles arbitrary shapes, text, and images and allows all of these to be rotated, scaled, skewed, and otherwise transformed in a uniform manner. A code example would be:

import java.awt.*;
import java.awt.geom.*;
public class r extends Frame {
 



    public static void main(String args[]) { new r(); }
 



    r() { setSize(200,200); setVisible(true); }
 



    public void paint(Graphics g) {
        Graphics2D g2D = (Graphics2D) g;
        AffineTransform aft = new AffineTransform();
        aft.setToTranslation(100.0, 100.0);
        g2D.transform(aft);
        aft.setToRotation(Math.PI / 8.0);
        String s = "Rotated Hello World";
 



        for (int i = 0; i < 16; i++) {
            g2D.drawString(s, 0.0f, 0.0f);
            g2D.transform(aft);
        }
    }
}

There is more info about the 2D API at http://java.sun.com/products/java-media/2D/index.html and http://developer.javasoft.com/developer/technicalArticles/

  1. (Sect. 10) How do you change the font type and size of text in a TextArea?

*Like this.

myTextArea.setFont(new Font("NAME", <STYLE>, <SIZE>));

where:

Example: new Font("TimesRoman", Font.PLAIN, 18);

  1. (Sect. 10) Can you have different fonts for individual words in a TextArea?

*No. If you're trying to write a word processor, use the Swing JText classes.

  1. (Sect. 10) How much text can be put in a TextArea?

*TextArea just uses the corresponding widget of the underlying window system. It will be bounded by the limit imposed in the native window system. In Windows 95 TextAreas can hold about 28Kb. The native widget allows 32Kb, but there is some overhead which reduces the amount available to the programmer. The limit is removed in JTextComponent in Swing (JDK 1.2) which dispenses with peer controls.

  1. (Sect. 10) How do I clear the contents of a TextArea?

*Set it to an empty String with this:

area.setText("");
  1. How do I get back to a normal echo after I have used TextField.setEchoChar('*')?

*TextField.setEchoChar('\0') works on most Windows-based browsers...but for most other platforms (i.e. Netscape under UNIX), it just locks up the textfield.

There is only one good solution, and that is to make two TextFields on top of each other, one normal, and one with .setEchoChar('*'), and switch between them.

  1. (Sect. 10) How do I get word wrap in a TextArea?

*It's a little obscure. Creating a TextArea with no horizontal scrollbar causes wrapping to occur automatically. The idea is that if you ask for a scroll to scroll viewing over to the right, there is no reason for the widget to do word wrap. So take away the scrollbar, and word wrap will be done instead.

Supply TextArea.SCROLLBARS_NONE or TextArea.SCROLLBARS_VERTICAL_ONLY to the TextArea constructor to get word wrap. By default, a TextArea is created with both horizontal and vertical scrollbars.

  1. (Sect. 10) How can I limit a TextField to no more than N characters, or to only allow numeric input?

*The approach is to look at keystrokes as they happen, and disallow input that does not meet your criteria.

A neat variation is to extend the basic AWT component, and in your subclass also include the handler that will look at the keystrokes. This bundles everything neatly in one place. The code may look like:

import java.awt.*;
import java.awt.event.*;
 



public class XCTextField extends java.awt.TextField implements
java.awt.event.TextListener {
 



    public XCTextField(int columns) {
        super(columns);
        enableEvents(AWTEvent.FOCUS_EVENT_MASK);
        addTextListener(this);
    }
 



    // other constructors may be useful, too
 



    public void textValueChanged(java.awt.event.TextEvent event) {
        int col = this.getColumns();
        int len = getText().length();
     // int caret = getCaretPosition();
 



        if (col > 0 && len  > col) { 
        // or if the char just entered is not numeric etc.
                String s = this.getText(); 
                Toolkit.getDefaultToolkit().beep();  
                this.setText(s.substring(0,col));  
                this.setCaretPosition(col-1);  // caret at end 
        }   
 



    } 
 



    public void processFocusEvent(java.awt.event.FocusEvent e) {
    // this routine highlights according to focus gain/loss.
        super.processFocusEvent(e);
        int id = e.getID();
        if (id==java.awt.event.FocusEvent.FOCUS_GAINED)
            this.selectAll();
        else if (id==java.awt.event.FocusEvent.FOCUS_LOST)
            this.select(0,0);
    }
}

Here is a much briefer example, which very cleverly does the work in the Listener. Oracle really dislikes the "apostrophe" character in a data text fields, as it is interpreted as part of an SQL statement. Here is the code that James Cloughley wrote to suppress apostrophes ("ticks") in a TextField.

import java.awt.*;
import java.awt.event.*;
public class NoTick extends KeyAdapter {
    final char tick = '\'';
 



    public void keyPressed( KeyEvent event ) {
        TextComponent tc = ( TextComponent )event.getSource();
        char c = event.getKeyChar();
        if ( c == tick ) { event.consume(); }
    }
}

Use it like this:

TextField sometextfield = new TextField();
sometextfield.addKeyListener( new NoTick() );
    

Brief and clever - make the event handler consume unwanted characters. However, it doesn't filter out text that arrives in the component via cut & paste! If you use ctrl-v to paste, you get key events for the ctrl and v, but not for the characters that are pasted.

Finally, check out iDate, iTime, and iNumeric from IBM's alphaworks javabeans, available free at http://www.alphaworks.ibm.com/alphaBeans/. These beans do the kind of validation you want.

Size and Position

  1. (Sect. 10) I use add(Component) to add Components to the Container. Is there any way to explicitly set the z-order of these Components?

*JDK 1.0 has no way to explicitly set the z-order of components. You can try it heuristically, based on the browser you're using, or you can use CardLayoutManager to ensure the panel you want is at the front.

In JDK 1.1, the z-order of components ("z-order" means "front-to-back" order, i.e. which window is in front of which) can be controlled by using the the method add(Component comp, int index). By default, components are added 0 to N. The method paint of class Container paints its visible components from N to 0.

  1. (Sect. 10) How can I get the dimensions and resolution of the screen?

*Use

java.awt.Toolkit.getDefaultToolkit().getScreenSize()

or

java.awt.Toolkit.getDefaultToolkit().getScreenResolution()

Screen resolution is in dots-per-inch.

Take a look in the Toolkit class for other useful methods.

Toolkit.getDefaultToolkit().getColorModel().getPixelSize() 

gets you the color model in terms of bits per pixel.

Math.pow(2, Toolkit.getDefaultToolkit().
    getColorModel().getPixelSize())

gets you the color model in terms of number of colors. Or use this:

1 << Toolkit.getDefaultToolkit().
    getColorModel().getPixelSize()

That does a shift left to calculate the power of two.

  1. (Sect. 10) How do I allow for the size of the title bar and border when I draw a Frame?

*Use MyFrame.getInsets(). This returns a java.awt.Insets object which has four ints: top, left, bottom, right, giving the number of pixels each of those margins are inset from the top. You can use these value to adjust the Dimension object returned by component.getSize().

If you are doing this in the constructor you need to ensure that the Frame's peer object is created first. Otherwise the Insets object returned by getInsets() will have all zero values. Make a call to Frame.addNotify() to have the peer created.

  1. (Sect. 10) How do I resize a List? I had a List defined as
List tlist = new List(10);



but the Strings in the list were 80 characters long and only the first 15 were being shown. I was not able to resize the List to display the contents without using the scroll bar.

*A List cannot be resized in a constructor, so add the following to the Applet (or wherever):

public void paint (Graphics g) {
    tlist.setSize(200,200);
}

Then before showing panel/frame with the List:

tlist.resize(400,400);
  1. (Sect. 10) How can my program tell when a window is resized?

*Add a ComponentListener to the window and fill in the componentResized() method with what you want to do when the window is resized. A less-satisfactory alternative is to override the setBounds(int,int,int,int) method of Component to do what you want. Of course, have it call super.setBounds() as well. Note that setBounds() replaces reshape() which is deprecated.

Note the new APIs call the deprecated APIs instead of the other way round. For example, Component.setBounds calls Component.reshape, instead of reshape calling setBounds. This is because the AWT sometimes needs to call these for its own purposes. If it called the old one which then called the new one, and you overrode the new one, the AWT would (wrongly) not call your routine. By having the AWT call the new one (and then the new one call the old one), any overrides of the new one will correctly be called by the AWT as needed. If that didn't make sense, forget I mentioned it.

  1. (Sect. 10) How do I center a dialog box?

*You cannot currently get the applet's absolute screen coordinates. Its location (0,0) is relative to the browser, not the screen itself. But you can center something that it pops up or displays centered on the screen with code like this:

Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
my_window.move(
 ( screen.width - my_window.size().width ) / 2,
 ( screen.height - my_window.size().height ) / 2 );
 



my_window.show().

In a related fashion, you can center something on its parent like this. Note the intelligent use of APIs like translate() to do the work for you.

void center(Component parent) {
    pack();
 



    Point p = parent.getLocation();
    Dimension d = parent.getSize();
    Dimension s = getSize();
 



    p.translate((d.width - s.width) / 2,
                (d.height - s.height) / 2);
    setLocation(p);
}
  1. (Sect. 10) How can I get the absolute mouse coordinates?

*You mean, if the browser is about 640x480, you want a y-coord between 0 and 480. If the browser window is about 800x600 you want a y-coord between 0 and 600. This might be needed for a pop-up menu, where you want to pop up at the absolute mouse position.

The approach is to sum up the event's (x,y) and the locations of the target and its parents until there is no parent. Though on some browsers, it seems this is not reliable. [Better suggestions are solicited.]

  1. (Sect. 10) How do I detect a resize of a Frame or other Component?

*If you are using JDK 1.0.2, you can override the reshape(int, int, int, int) method of Component to do what you want; of course, have it call super.reshape() as well.
In JDK 1.1.x, setBounds() replaces reshape(), which is deprecated - however, there is a better way of detecting the resize using the new event model, than overriding setBounds(). Note the new APIs call the depecated one.

The proper way to detect the resize in 1.1.x is to register a ComponentListener on the Frame, like this:

import java.awt.*;
import java.awt.event.*;
 



class MyFrame extends Frame {
    public MyFrame() {
        addComponentListener(new CmpAdapter());
    }
 



    class CmpAdapter extends ComponentAdapter {
        public void componentResized(ComponentEvent evt) {
            //doSomething();
        }
    }
}

Alternatively, the same effect can be achieved like this:

class MyFrame extends Frame implements ComponentListener {
    public MyFrame() {
        addComponentListener(this);
    }
 



    public componentHidden(ComponentEvent evt) { }
    public componentMoved(ComponentEvent evt) { }
    public componentShown(ComponentEvent evt) { }
    public componentResized(ComponentEvent evt) {
        //doSomething
    }
}

Or even with an anonymous inner class

  public MyFrame() {
    addComponentListener(new ComponentAdapter() {
      public void componentResized(ComponentEvent evt) {
        // doSomething;
        }
      } );
    }
  1. (Sect. 10) What are those preferredSize() and minimumSize() methods in Component?

*Those methods allow a LayoutManager to calculate the preferred and minimum sizes of the Components it is arranging. You can control the values that the LayoutManager gets by creating subclasses of the Components you are using and overriding these methods. You don't call them; you override them and they are called on your behalf.

  1. (Sect. 10) Why isn't my component showing up at all? Or in some cases not until I resize the main window?

*The initial sizes of components are not always exactly what the programmer would expect. When a component doesn't show up, often it is getting added to its parent, but with a size of 0x0. Even when getPreferredSize gives a non-zero value. If this seems to be what's happening, try calling setSize(getPreferredSize()).

If that doesn't seem to be the problem, then sometimes the fix is to call validate() after the components have been added. This causes the layout manager to re-layout the components and make them visible. Sometimes this is an issue if many components are removed from a container and another set is added, while the container remains visible.

  1. (Sect. 10) The JVM always defaults to the current display. Is there anyway to change that?

*If you're running on X, set the environment variable DISPLAY (e.g. setenv DISPLAY mymachine:0.0). You might have to use xhost on the target to permit the connection to be made.

If you're using windows, mac or some other system then you're stuck with VNC. See http://www.uk.research.att.com/vnc

Drawing and Pixels

  1. (Sect. 10) How do I plot a single pixel to the screen?

*Use g.drawLine(x1,y1,x1,y1) to draw a line one pixel in length. If you are drawing a very large number of individual pixels, consider using a java.awt.MemoryImageSource object and measure whether this offers better performance.

  1. (Sect. 10) Is it possible to draw a polygon or a line more than 1 pixel wide?

*JDK 1.1 doesn't have support for this. The standard workaround for drawing a thick line is to draw a filled polygon. The standard workaround for drawing a thick polygon is to draw several polygons.

There is a useful class at http://www.apl.jhu.edu/~hall/java/GraphicsUtil.html which extends the drawxxx and fillxxx methods of java.awt.Graphics. It adds a Line Width argument to most of the drawxxx methods, a Color argument to most of the drawxxx and fillxxx methods, and a Font argument to drawString and drawChars.

JDK 1.2 introduces the java.awt.BasicStroke class. You set the stroke on a Graphics object, and line rendering is done using that info.

        BasicStroke bs = new BasicStroke(width, BasicStroke.CAP_BUTT,
                                 BasicStroke.JOIN_MITER, 1.0f, null, 0.0f);
        g.setStroke(bs);
        g.drawLine( ... );
  1. (Sect. 10) How can I make an offscreen image with transparent pixels?
    How can I grab the pixel values from an offscreen image?
    How can I use AWT drawing primitives (e.g. drawString() or drawOval()) on an image I created from an ImageProducer?

*None of these things can be done in JDK 1.1. Most (possibly all, subject to confirmation) can be done in JDK 1.2.

The code in JDK 1.1 behaves as though there were two unrelated types of Image. The first type are those created by the Component.createImage(int, int) call, known as "offscreen" images, and the second are those created by the Component.createImage(ImageProducer) call, or by the Toolkit/Applet.getImage() calls, which I will call "produced" images.

The only common ground between these kinds of Image in JDK 1.1 is the following:

The differences between these objects are the following:

In these cases, "you may not" generally means "you may not successfully". Symptoms on attempting these range from Exceptions to garblings of the Image. Any or all of these restrictions may be removed in Java 1.2, which features a new 2D API. If you have tried it, let me know.
Workaround: cause a peer to be created for the Image, and then do the operation. It will work. You can add it to a Frame, for example. You do not have to show() the Frame. Causing the peer to be created is enough.

There are some relevant bugs shown in the Java Developer Connection: Bug ID 4098505. Apparently, from the report from the Sun engineer, PixelGrabber is specified to work with offscreen images, just it is currently buggy, and invariably gets the wrong color model. No fix has been scheduled yet.

Bug ID 4077718 reports that setting transparent Colors in offscreen images has been available since Java 1.2b1. I am personally unable to verify this.

There is an incorrect answer from Sun to the third matter, of getGraphics() on produced images, in article 1501 in Questions&Answers.

  1. (Sect. 10) How can I grab a pixel from an Image object?

*This is the purpose of the java.awt.image.PixelGrabber class. A fragment of code showing its use is:

import java.awt.image.PixelGrabber;
import java.awt.Image;
   ...
public static int pixelValue(Image image, int x, int y) {
// precondition: buffer must not be created from ImageProducer!
// x,y should be inside the image, 
// Returns an integer representing color value of the x,y pixel.
    int[] pixel=new int[1];
    pixel[0]=0;
 



// pixel grabber fills the array with zeros if image you are
// trying to grab from is non existent (or throws an exception)
    PixelGrabber grabber = new PixelGrabber(image,
                                     x, y, 1, 1, pixel, 0, 0);
    try {
        grabber.grabPixels();
    } catch (Exception e) {System.err.println(e.getMessage());}
    return pixel[0];
}

By the way, one issue on working with images is that the Java VM will consume virtual memory pretty fast if you are loading lots of images without calling the Image.flush() method when done. The getImage() method probably caches old images so they aren't garbage collected.

Other AWT FAQs

  1. (Sect. 10) Why does my pop-up menu only work on Windows (or on Unix)?

*The popup trigger is platform dependent. On Windows, the MOUSE_RELEASED event identifier is the popup trigger. On Unix, the MOUSE_PRESSED identifier triggers the popup. To keep your code cross-platform, you need to use the isPopupTrigger() method in both the mousePressed() and mouseReleased() event handlers:

public void mousePressed(MouseEvent me) {
  if (me.isPopupTrigger())
    doPopupStuff();
  else
    doRegularMousePressedStuff();
}
 



public void mouseReleased(MouseEvent me) {
  if (me.isPopupTrigger())
    doPopupStuff();
  else
    doRegularMouseReleasedStuff();
}
  1. (Sect. 10) How do I change the icon on my Frame or JFrame from the Java coffee cup to my own icon?

*Just use

f.setIconImage( Toolkit.getDefaultToolkit().getImage(iconfilename) );

On Windows, the icon must be 16-by-16 pixels.

  1. (Sect. 10) What's all this about subclassing Canvas and overriding paint() ? Can't I just do a getGraphics() for a component, and draw directly on that?

*You can do that, and it might work up to a point (or it might not). A problem arises when the window system wants to refresh that component e.g. because it has been partially obscured and is now revealed. It calls paint(), and paint() has no knowledge of the other g.drawing() you have just done.

  1. (Sect. 10) But couldn't the AWT just remember what has been drawn to a Graphics context, and replicate that instead of calling paint()?

*Possibly it could, but how do you unremember something that has been drawn? How do you start drawing over again with different contents? You could solve these by creating extra methods, but that is not how it works. In practice it is a lot simpler to be able to look at the paint method, and see explicitly all the things that will be done to draw that component. Bottom line: Use paint(), not g=getGraphics(); g.drawString( ...

  1. (Sect. 10) When I call repaint() repeatedly, half my requests get lost and don't appear on the screen. Why is this?

*repaint() just tells the AWT that you'd like a paint to happen. AWT will fold several adjacent repaint requests into one, so that only the most current paint is done. One possible workaround might be to use a clip rectangle and only paint the different areas that have changed.

  1. (Sect. 10) Why do I get this when using JDK 1.1 under X Windows?
30.java.lang.NullPointerException



31.at sun.awt.motif.MFramePeer.<init>(MFramePeer.java:59)



32.at sun.awt.motif.MToolkit.createFrame(MToolkit.java:153)



33.at java.awt.Frame.addNotify(Frame.java)



34.at java.awt.Window.pack(Window.java)



*There's a missing font on your system. Move font.properties from the "lib" subdirectory aside to font.properties.bak. Then it won't look for the font and fail to find it.

The problem occurs because the Motif AWT libraries use the Font "plain Dialog 12 point" as a fall-back default font. Unfortunately, when using a remote X server sometimes this font isn't available.

On an X terminal, the diagnostic may be slightly different, a segv

% appletviewer HelloWorldApplet.html
SIGSEGV 11* segmentation violation
si_signo [11]: SIGSEGV 11* segmentation violation
si_errno [0]: Error 0
si_code [1]: SEGV_ACCERR [addr: 0x14]

To determine which fonts you have, issue a command such as

xlsfonts > ~/fonts.txt

Then pick through the long list of fonts to determine which ones you want to use. The xfd program will let you look at a font:

xfd -fn "your font name here" &
  1. (Sect. 10) Why is GridBagLayout so hard to use?

*There are two reasons. First, while simple layouts are easy. detailed GUI layout is difficult. Second, GridBagLayout wasn't designed with human factors and ease of use in mind. If that bothers you (it bothers me) then don't use it. Create your GUI on several panels and use the other layout managers as appropriate to get the exact effect you want. The official story from the project leader of the AWT project, as explained to the Mountain View Java Users Group on December 4 1996, is:

"The case has been made and is now accepted that GridBagLayout is too hard to use for what it offers. GBL will continue to be supported, and something better and simpler will eventually be provided as well. This 'better GBL' can be used instead of GBL."

Bottom line: nobody has to spend any effort on GBL, there are simpler alternatives available now. In addition GBL is the source of a memory leak. GBL puts "added" components into a hashtable, but removeLayoutComponent() never removes them. See bug 4170095.

GBL documentation is hard to come by. Based on the obvious similarity, it could have been derived from the Tk (of Tcl/Tk) grid layout manager. If you're not a fan of nesting panels, and none of the other layout managers do what you want (or you're working with legacy code that already uses it), you might find some Tk documentation worth a look.

JDK 1.0 defined the GridBagLayout but its tutorial appears buried in Swing: http://java.sun.com/docs/books/tutorial/uiswing/layout/gridbag.html

  1. (Sect. 10) MyClass works fine except when I try to set a particular font. I just can't seem to get it to work in Win95, but I can get it to work on a MacOS and Unix.

*You probably specified a font name that isn't available under your Win95 installation; this is one of those cross-platform differences that can bite you if you over-specify for one platform, like specifying "Arial" as a font and expecting it to work on something other than Windows.

On both Windows 95 and Solaris 2.6, these fonts

are revealed by this code:

import java.awt.*;
 



class foonly {
    static public void main(String s[])
    {
        String n[]= new Frame().getToolkit().getFontList();
        for (int i=0;i<n.length; i++)
            System.out.println(n[i]);
 



        System.exit(0);
    }
}

In other words, You can get a String array of the names of the fonts by

String[] fonts = Toolkit.getDefaultToolkit().getFontList()

The names of actual fonts like Helvetica, TimesRoman, and Courier are deprecated in JDK 1.1 in favor of font styles like SansSerif, Serif, and Monospaced (respectively). The font style will be mapped into the nearest actual font on a platform.

The font styles are now mapped into a system font name using the entries in one of the font.properties files in $JAVAHOME/lib. There are multiple font.properties files corresponding to different locales. If you wanted a quick hack for testing, you could modify the file or add to it so a different mapping is done to a new font you want to try.

  1. (Sect. 10) I've made a Lightweight Component (a Component directly extending Component), and it keeps flickering/doesn't repaint itself properly. Why is this?

*Lightweight Components, since they are notionally meant to be "transparent", aren't painted directly in response to repaint(), but in fact, Component.repaint() goes up the stack of Components until it finds an "Opaque" Heavyweight Component (necessarily a Container), and then calls repaint() on *that*.

At this point, a call is eventually scheduled to Container.update(). His first action is to call super.update, plunging us into Component.update(), which clears the component to the background color, since it has been called on a heavyweight, and returns. Then Container.update() proceeds merrily to call update on all contained Lightweight Components, recursively.

The bottom line: "transparency" of lightweight components will only work correctly (without flickering) if the first upwardly accessible heavyweight component in the containment hierarchy is

If this is not done, the default Component update() will always clear the background before any repainting is done, leading to annoying flickering.

Another important point is that if your Container has its own paint() method, that paint method of the container must call super.update/paint(), otherwise the contained lightweight components will never be painted. Putting this all together, the minimal alteration to code to cause it to work in this case is to place the method

public void update(Graphics g) {
    super.paint(g);
}

in the most closely containing heavyweight Container, in a Component hierarchy where you want to smoothly render lightweights that do not paint areas extending past that painted by their parents, i.e. ones that are not "transparent". This is dirty, but quick.

If you want smooth transparency, the call above should read

 
  public void update(Graphics g) {
    // standard offscreen generation here.
    offg.fillRect(required background colour, full size);
    super.paint(offg);
    g.drawImage(myimage, 0, 0, null);
    }
 



  public void paint(Graphics g) {
    // can generally expect resizes will hit update() first.
    super.paint(offg);
    g.drawImage(myimage, 0, 0, null);
    }

It's possible to intertwine these, by having this.update() calling this.paint(), with various replacings of the argument, but it is clearest to override them separately, as in the example.

  1. (Sect. 10) What is the difference between Component's setForeground(Color c) and Graphics's setColor(Color c) ?

*First of all, these methods do the same thing: Set the foreground color to the value of the parameter. The difference lies in where you use them. There is also a Component.setBackground that will set the background color.

If you are in a constructor or an event handler (e.g. "click here to turn the canvas blue") you have a Component and should use the setForeground() method. If you are in a paint() method, that takes a Graphics context as its argument so you will typically use g.setColor(c).

Unlike a Component, a Graphics object doesn't have a background color and a foreground color that you can change independently. A Graphics object arrives in the color(s) inherited from the drawing surface. From then on, any rendering (drawLine(), drawRect(), fillOval(), etc.) will be done in the setColor() color. Because they do different things, the Component and Graphics methods have different names.

  1. (Sect. 10) When I start a mouse drag inside a Component, and go outside the Component, still dragging, the mouse events still get sent to the Component, even though I am outside it. Is this a bug?

*No, it is the specified behavior. The Java API documentation says:

"... Mouse drag events continue to get sent to this component even when the mouse has left the bounds of the component. The drag events continue until a mouse up event occurs...."

It is done for the convenience and ease of the application programmer. It allows you to handle all drags from the place of origin. If you don't want this, simply look at the coordinates of the mouseDrag Event, and if they are outside the Component, ignore them.

  1. (Sect. 10) Why doesn't my window close when I click on the X in the title bar?

*Here's how to make your program do that.

  1. (Sect. 10) How can I force a synchronization of the graphics state, e.g. of a cursor change, or an animation frame to be rendered?

*This is done by the sync() method in Toolkit. So just use:

AnyComponent.getToolkit().sync();
  1. (Sect. 10) How can I tab between components?

*In JDK 1.0, you have to read the key press, and program it explicitly. JDK 1.1 supports tab and shift-tab (previous field) automatically. The tab order is the order that the components were added to the container.

  1. (Sect. 10) What is the difference between "low level" and "semantic" events?

*Low-level events are tied to a specific component (resizing a window, dragging the mouse, striking a key, adding a Component to a Container, etc.). Semantic events are those generated when you frob a control (move a scrollbar, click on a button, select from a menu, etc.), and the same kind of event can be generated by several different components. A Button and a List both fire an Action event when they are clicked on.

To the programmer, the important difference is that you can change a low-level event such as the key value in a keypress, and it will display the new value. You can also consume low level events so that they do not appear in the widget. You can't do these things with semantic events - they have already "occurred" to the widget.

Semantic events: Use the method addXListener() to add a listener object which implements the XListener interface to get XEvent objects delivered (usually via the AWTEventMulticaster). Low level events: Use the method enableEvents() and override performX() to grab those events in the object itself.

  1. (Sect. 10) Is it possible to have a Java window float above all other windows. For example, a tool palette floats in a super-layer always above all the regular document windows on which you use the palette's tools?

*On MS Windows, a Window object floats above all other windows, unlike a Frame, which is layered in with ordinary windows. This behavior yields a "floating" effect. Whether a Window object is really supposed to float is another question entirely.

On Mac, a Window object is either layered in with other windows, just like a Frame is, or else it is entirely modal - depending on which VM you use. In Java - there appears to be no easy way to get floating behavior. If anyone knows otherwise, please send in your comments.

  1. (Sect. 10) How can iconify/deiconify a window?

*JDK 1.1 had no way to write code to force a window to iconify or deiconify. Support was added in JDK 1.2.

     MyFrame.setState( Frame.ICONIFIED );
     MyFrame.setState( Frame.NORMAL );

will do the trick. There is a corresponding getState();

  1. (Sect. 10) How do I know which mouse button was pressed, and how often?

*To handle mouse events you have to implement the MouseListener interface, or derive from the MouseAdapter class in order to use one of the mouse-handling methods. The MouseEvent argument passed to the handling methods contains fields that say which button was pressed, and the click count. Use code like this.

public void mouseClicked(MouseEvent m) {
 boolean leftButtonPush   = 
    (m.getModifiers() & java.awt.event.InputEvent.BUTTON1_MASK) != 0;
 boolean centerButtonPush = 
    (m.getModifiers() & java.awt.event.InputEvent.BUTTON2_MASK) != 0;
 boolean rightButtonPush  = 
    (m.getModifiers() & java.awt.event.InputEvent.BUTTON3_MASK) != 0;
 



 int click = m.getClickCount();    // might be 1,2,3 clicks or more

You can also call at m.isPopupTrigger(). If it returns a true value, the user has asked for a pop-up menu. On a lot of window systems, the right mouse button is the trigger for pop-up menus.

You can overload processMouseEvent for your component.

public void processMouseEvent(MouseEvent e) {
    if (e.isPopupTrigger())  {
       // do what you want
    }
    else
      super.processMouseEvent(e);
  }

The code above applies to JDK 1.1. You can also call java.awt.swing.SwingUtilities.isRightMouseButton(MouseEvent me).

See also question 15.10.


11. Swing Technology

  1. (Sect. 11) What is Swing?

*Swing technology is a new GUI toolkit bundled with JDK 1.2, and available as an add-on extension library for JDK 1.1. Swing technology is part of the Java Foundation Classes and supports a GUI toolkit that lets developers create components that have a pluggable look-and-feel. From an architectural standpoint, the Swing component set extends - but does not completely replace - the Abstract Windowing Toolkit (AWT).

Swing technology has many components that can be used in place of components in the AWT (e.g. JFrame instead of Frame, JButton instead of Button, JApplet instead of Applet, JPanel instead of Panel). It also has many components that don't exist in the AWT (e.g. tool tips, toolbars, and progress bars). However Swing technology relies on the underlying AWT being there.

The Swing toolkit allows the creation of GUI's that are every bit as sophisticated as native code toolkits like MFC -- with the Java technology advantage that they run on every platform. The pluggable look and feel means that they can have the same appearance on every platform, or you can choose to have it look like Windows on a PC, like Motif on a Unix box, etc, just as the user chooses.

Swing technology also supports the Accessiblity API. That API allows the adaptive software used by disabled computer users to directly query the Java VM and extract information about the running program, the usual purpose for this being to determine the UI components. Then the existing adaptive software can interpret it to the user (e.g. read the contents of a window, etc). Swing technology doesn't use native components, and the adaptive software taps into native components, so the accessibility API has a real role in bringing the two together. The beauty of the Accessibility API is that developers need to do little work to support it, but they do need to be made aware of it if they implement new components.

With Swing technology, native window behavior is confined to external window frames (and their borders) and a few other things such as fonts and the buffers used to hold window contents. The composition, layout, and drawing of controls is now all handled by Java code. So identical code is executed to create and manage your user interface on every platform. Swing provides a much greater consistency of behavior across different platforms.

Swing works with JDK 1.1 if you download the swing.jar file and add it to your path. Swing is built in to JDK 1.2, and Javasoft has just changed its 1.2 Swing package-naming strategy. It is now called javax.swing.

  1. (Sect. 11) Should I use Swing technology or AWT to build my GUIs?

*Use Swing technology to build your apps now instead of AWT components, wherever you have a choice. Swing is a GUI toolkit that is at least as good as other commercial GUI toolkits, and better in several respects.

With Swing technology, it is easier to build an application that is portable between Mac, Solaris, Windows 95 and NT, than it is to use Win32 and build an application that just runs on Windows 95 and NT.

  1. (Sect. 11) Where can I find a Swing technology tutorial?

*There is a tutorial at http://java.sun.com/docs/books/tutorial/ui/swing/index.html which is part of this tutorial: http://java.sun.com/docs/books/tutorial/ui/TOC.html
There is also a Swing technology FAQ at http://www.drye.com/java/faq.html
See also http://www.codeguru.com/java/Swing/index.shtml
There is a Swing Developer Connection website with white papers and examples at http://www.theswingconnection.com/.
Please let this FAQ maintainer know about other good Swing tutorials and online resources.

  1. (Sect. 11) What is the Model/View/Controller paradigm?

*Model/View/Controller is a design pattern or framework originally developed by Prof. Trygve Reenskaug at Xerox PARC in 1978/9. MVC was developed to allow Smalltalk to conveniently support GUIs.

Model/View/Controller is used in Swing in the more complicated widgets like JTree and JTable. Basically, the "model" contains your data, the "view" is the graphical representation, and the "controller" is responsible for the interaction between the other two. As an example, think of visually editing the Tree widget that represents a directory. The display is the view. Selecting a file, and dragging it to the trash can will delete the file. In order for the delete to happen, the controller must tell the model what just happened in the view.

In practice, inter-communication between the view and the controller is complex, so the two are bundled together in one category in Swing. The model (data) is separate though.

There's a reasonable white paper on MVC in Swing at http://java.sun.com:81/products/jfc/swingdoc-static/swing_arch.html .
There is information on other OO design patterns at http://www.parallax.co.uk/cetus/oo_patterns.html.

  1. (Sect. 11) When I run the Swing technology demo on Windows 95 I get an error "Out of environment space."

*That's because you don't have enough space for your DOS environment. You can fix this with:

  1. (Sect. 11) My Swing program runs fine on one of my MS Windows machines, yet fails to draw correctly on the other. Why is this?

*Odd painting behavior on one MS Windows system, when the program works fine on another system is usually caused by some of the following:

  1. (Sect. 11) How can I run Swing technology-based code in a browser?

*Most current browsers have to be specifically set up to run Swing applets. Read the article at http://java.sun.com/products/jfc/tsc/web/applets/applets.html for information about this. The article also contains a simple Swing example applet, so you can confirm that that's your problem.
Another approach is to use the Java plug-in, which automatically gives Swing technology in the browser. See http://java.sun.com/products/jfc/tsc/swingdoc-current/java_plug_in.html

  1. (Sect. 11) Why is my menu showing up behind other components when I use Swing technology?

*The answer relates to lightweight and heavyweight (peer-based) components. There is a good article about it at http://www.javasoft.com/products/jfc/swingdoc-current/mixing.html

For those who want the quick fix, and will read the article later, adding the line:

javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);



before you create any menus will probably fix it (even if you're using menus other than JPopupMenu).

The summary answer is that a Lightweight component will not appear over a heavyweight component by default.

  1. (Sect. 11) Why is there no JCanvas? How do I get a lightweight Canvas?

*Use a JPanel as a Swing replacement for Canvas. All Swing components have a paint(Graphics) routine that you can override, just as you would have with Canvas, (but you probably want to override paintComponent(Graphics) instead, see next question).

  1. (Sect. 11) Why don't the borders of my Swing components look right when I override paint(Graphics)?

*Swing technology splits painting into several different routines:

all of which are called from paint(Graphics). If you override paint(), unless you remember to do it, the paintBorder() and paintChildren() won't get done.

In most cases, what you really want to do is override paintComponent() instead of paint().

  1. (Sect. 11) Why does my JFrame go away after I choose system close on the window?

*Assume that you have a Swing JFrame component, and you handle the windowClosing event, but do nothing in the handler. You will see that the JFrame disappears anyway.
The reason is that JFrame's have default handling of the system close operation, separate from the windowClosing event. You have to override that by calling:

   setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

on your JFrame.

  1. (Sect. 11) Why can I run the Mac Look and Feel only on Mac OS?

*(This answer comes from the Swing Connection, see http://java.sun.com/products/jfc/tsc/swingdoc-current/911.html).
Sun has not determined that it has the right to deliver the Mac look and feel on platforms other than MacOS. If Apple were to confirm Sun's right to deliver this look and feel on other operating systems, Sun would be delighted to remove the lock. To date, Apple has declined to do this.

Although you cannot use the new Mac L&F on non-Macintosh platforms, there is a way to examine the source code so developers can use it as an example of how to create a custom L&F. The Mac L&F is distributed in "stuffed-binhexed" format, which is standard for the Macintosh. If you develop on a MS-Windows platform and would like to examine the source code for the Mac L&F then you can do that by downloading and using a program called Aladdin Expander for Windows. You can download Aladdin Expander from this URL: http://www.aladdinsys.com/expander/index.html When you have downloaded Aladdin Expander, you can use it to decode the Mac L&F file posted on the JDC.

A recent posting on comp.lang.java.gui suggested the following user workaround:

import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
class MyOwnWindowsLookAndFeel extends WindowsLookAndFeel {
    public isSupportedLookAndFeel() { return true; }
}

The desire on Sun's part to avoid infringing the Windows Look and Feel is also the reason why the JTree uses colored circles (and soon, little circles with a short line coming out of them) for the nodes to indicate whether they are open or not. The Swing team could have used the '+' and '-' as Windows does, or even the triangles that MacOS uses, but decided against it.

  1. (Sect. 11) When I set the cursor to WAIT_CURSOR why does it only change when my cursor is over specific components?
    or
    How can I change the cursor to a WAIT_CURSOR over my entire window and all of its components, preventing any user action, while some other process is happening. (i.e. database access, opening another window, downloading an image, sorting some data, etc.)

*In JDK 1.0.2 only the awt Frame could change its Cursor. With the advent of JDK 1.1 the Cursor manipulation has been move to the Component clss. Now all Components have access to the Cursor class.

You could change your Cursor to a WAIT_CURSOR for each Component. This could be time-consuming. You could have a potentially large number of Components. With the advent of the JFC Swing, there is a mechanism to change the Cursor over the entire Window regardless of the number of components. The Swing component JFrame has a method:

             public void setGlassPane(Component glassPane)

which sets an awt Component as the 'glassPane' for the JFrame.

This Component will cover the entire JFrame's visible user accessible (when visible), area excluding the border set by the underlying windowing system. With the 'glassPane' Component you can set the 'WAIT_CURSOR' over an entire JFrame, prohibiting user input (the 'glassPane' Component gets all user input) and blocking the user until your 'other' processing is complete.

NOTE: You must spawn a Thread to accomplish your 'other' work if you want to see the WAIT_CURSOR while the 'other' processing is happening. When the 'other' work is being accomplished, the 'glassPane' is visible with a WAIT_CURSOR and gobbling up all user input. When the 'other' work is finished, the Thread uses your waitCursor() method to hide your 'glassPane' until its needed again.

  1. (Sect. 11) Why does the compiler complain that the javax.swing.ProgressMonitor method "isCancelled()" isn't found?

*In American English there are two acceptable spellings: "canceled" and "cancelled". Note that the first one has one "el" and the second two "el's". Sun spells this "canceled" for ProgressMonitors but many of the secondary sources of documentation spell it "cancelled". To make matters worse, Sun spells it "cancelled" at other times, such as the method "isCancelled()" for PrinterJob.

  1. (Sect. 11) Why doesn't pressing the Enter key activate the default button on a Swing dialog?

*The default keymap for Swing text components (derived from JTextComponent) binds the Enter key (VK_ENTER) to the ActionEvent for text fields. This was done to be compatible with the behavior of java.awt.Textfield. To enable use of the Enter key to activate the default button, remove the Enter key binding from the default text component keymap as follows:

    static {
      KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
      Keymap map =
           JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
      map.removeKeyStrokeBinding(enter);
    }
  1. (Sect. 11) How do I create non-rectangular Components?

*Take a look at the following example that comes with the JDK:
$JAVAHOME\demo\awt-1.1\lightweight\RoundButtons\example.html

  1. (Sect. 11) How do I get my application to start up with the JFrame maximized?

*Sun left maximize / minimize / deiconify methods out of the AWT, and resisted putting them in for a long time. They finally added setState(NORMAL) and setState (ICONIFIED) in JDK 1.2, but there's still no explicit maximize call.

So get the screen size using Toolkit.getScreenSize(), and then use setBounds() or setLocation() / setSize() to move and resize the frame.

  1. (Sect. 11) How do I run Swing in my browser?

*You can set things up to run Swing classes and applets in a browser without using the plug in. You have to place the swing.jar library on the client, and tell the browser how to find it, but it works.


12. Browsers

  1. (Sect. 12) When will my favorite browser support Java 1.1?

*All popular browsers now have JDK 1.1 support. Netscape Communicator 4.04 plus patch "J" fully supports the features of Java 1.1. It was released in December 1997, and is only missing the JavaSoft support for applet signing (Netscape has gone its own way on this). See http://developer.netscape.com/support/faqs/champions/java.html#21
If you have Netscape 4.05, and the console says anything other than Java 1.1.5 then you do not have a fully 1.1 compliant Netscape. There is a special preview version available here: http://developer.netscape.com/software/jdk/download.html

Sun's HotJava browser fully supports the JDK 1.1 features. People who are obliged to use a browser without standard Java support should use the Java technology Plug-In. The Plug-In substitutes a standard virtual machine for the one that shipped with the browser. It allows you to use RMI, JavaBeans components, and Java Foundation Classes in Internet Explorer 3.02, 4.0, and 4.01. The Java Plug-In also works flawlessly with Netscape browsers. You can download the Java Plug-In from http://java.sun.com/products/.
Note that you need to change the HTML a little, to ensure that the plug-in JVM is invoked, not the browser JVM. A tool is included to do the changes automatically.

  1. (Sect. 12) What applet routines get called in various browsers and the plug-in on different browsing actions (back, forward, load, etc)?

*Java technology supporter Dave Postill did the work to get this answer.
The life cycle of an applet is illustrated by logging calls to init(), start(), stop() and destroy(). Use caution when your applets have threads since in most sample applet code, the stop() method calls stop on any separate threads within the applet, and then sets them to null.

This reckless threadicide is because most people think of the stop() method as something called only when the user leaves the page and wants to forget about it. But since Netscape calls stop() when you resize the window, your users would lose the applet's state when they thought they were only making a minor adjustment.

See "Java Tip 8: Threads, Netscape, and the resize problem - How to deal with applet resizing in Netscape Navigator", JavaWorld http://www.javaworld.com/javatips/jw-javatip8.html. Sadly the JavaWorld workaround does not completely fix the problem, since it relies on start() being called soon after stop() to identify a resize. However if you minimise the browser it may send a stop() to the Applet and then may not send a start() until the Browser is either restored or maximised. In this case, using the workaround results in the Applet being destroyed following minimising of the Browser - unless the Browser gets un-minimised within the killThreads timeout.

 

Netscape
[4.04/JDK 1.1.4]
[4.05/JDK 1.1.5]

Netscape with Plug-In [4.05/ JDK 1.1.5/ Plugin 1.1]

Applet- Viewer
[JDK 1.1.5]
[JDK 1.1.6]

Internet Explorer 4 SP1 4.72.3110.8
on NT 4.0 SP3

Internet Explorer
with Plug-In
[5.00.0518.10 / Plugin 1.1] on NT 4.0 SP3

1. Clear browser cache

nothing

nothing

nothing

nothing

nothing

2. Initial load of .html

init(), start() or init(), start(), stop(), start() [1]

init(), start()

init(), start()

init(), start()

init(), start()

3. Back

stop()

stop(), destroy()

[4]

stop(), destroy()

stop(), destroy()

4. Forward

start()

init(), start()

[4]

init(), start()

init(), start()

5. Reload

stop(), destroy(), init(), start()

stop(), destroy(), init(), start()

[4]

stop(), destroy(), init(), start()

stop(), destroy(), init(), start()

6. <shift> reload [NS],
<ctrl> reload [IE]

stop(), destroy(), init(), start()

stop(), destroy(), init(), start()

[4]

stop(), destroy(), init(), start()

stop(), destroy(), init(), start()

7. Resize

stop(), start()

[3]

[3]

[3]

[3]

8. Minimize

[2]

[3]

stop()

[2]

[3]

9. Restore

[2]

[3]

start()

[2]

[3]

10. Exit

stop(), destroy()

stop(), destroy()

stop(), destroy()

stop(), destroy()

stop(), destroy()

Notes:
[1] Results not repeatable.
[2] Not tested.
[3] Tested, and found that no logged methods are called.
[4] Test not applicable.

  1. (Sect. 12) Is it possible to set and retrieve cookies, in a manner that is compatible with all browsers supporting cookies?

*Short answer: no.
Longer answer: probably no.
Ultimate answer:
A cookie is a morsel of tasty data that a server sends back to the client, and can retrieve on demand. It allows the server to retain some state information for each of its clients. The information is typically something like "what pages has the user seen?" or "is this a privileged user?".
The DevEdge site on Netscape's home page has a Javascript-Java programming language example on getting cookies. Also http://www.geocities.com/SiliconValley/Vista/1337/ has info on connecting an applet with JavaScript functions. It's quite involved. Stick to just Java programming language if you can.

  1. (Sect. 12) I am developing an applet and testing it in Netscape Navigator. I find that after I recompile, I press reload, clear the caches, retype the URL of the HTML wrapper, and I still have the old version. Why is this?

*Note: a reader reports that as of Netscape Communicator 4.05 it is possible to force the browser to reload the applet by holding down "control"+"shift" while clicking "Reload"
In the past Netscape has completely failed to improve the defective code that does this monstrously wrong thing. It has been like this for many successive releases.
Flushing the network cache will make no difference; that isn't where the caching is taking place. Although applets are sometimes "pruned" and their ClassLoaders garbage-collected, this doesn't happen predictably, so restarting Netscape is the only reliable work-around at the moment.

  1. (Sect. 12) Why didn't Netscape reload the applet when you pressed the Reload button?

*For the applet to be reloaded, the new version would have to be loaded in a different ClassLoader. Navigator/Communicator's policy for assigning ClassLoaders to applets doesn't take into account whether a reload has been done (although there is no technical reason why it couldn't).
Some versions of Netscape reload the Applet if you use Edit/Preferences/Advanced/Cache to Clear Memory Cache and Clear Disk Cache, then <Shift> while you click on reload.
In Explorer, use View/Options/General/Delete Files, then <Control> 'Reload' button to reload the page containing the applet.

Until they fix it, use the appletviewer to test applets. And send them mail - developers can only fix the bugs they know about.

  1. (Sect. 12) Should I use Microsoft CAB files or Java programming language JAR files?

*The question contains its own answer.
CAB format is a Microsoft-only format. So do not use it as it destroys software portability.
JAR format is the Java programming language standard format, based on PKZIP format including data compression. JARs were introduced with JDK 1.1.
See http://www.ibm.com/java/community/viewarchive4.html for more information.
You should use the Java standard format JAR (Java Archive) files, not a vendor-specific format. JAR files are not just a Java standard, they are in industry-standard PKZIP format. One reader comments that both formats can be used with this tag:

<APPLET NAME=myapplet
ARCHIVE="myzip.zip"
CODE="com/nnnnn/nnnn/cccccccc.class"
WIDTH=n
HEIGHT=n>
<PARAM NAME="cabbase" VALUE="mycab.cab">
</APPLET>

IE3 does not support JAR
IE4 supports compressed and uncompressed JAR, but not signed JAR

  1. (Sect. 12) How can I tell the version of Java programming language that my browser supports?

*See http://java.rrzn.uni-hannover.de/insel/beispiele/vertest.html. This page tells you whether your browser supports JDK 1.1.

See http://www.uni-kassel.de/~pfuetz/Properties.html This page tells you which classes you may expect to be present in the browser's runtime.

  1. (Sect. 12) How can I tell the options/commands that Netscape's JVM takes?

*You can open the Java Console and type a "?" to get a list of all the commands/options available to you in Netscape's built-in JVM.


13. Applets

  1. (Sect. 13) What is the difference between an application, an applet, and a servlet?

*An applicationis a standalone program.
An applet is a downloadable program that runs in a web browser. Typically an applet has restricted access to the client system for reasons of security. Other than that it is virtually no different from a regular Java technology-enabled program.
A servlet is a Java technology-enabled program whose input comes from a server and whose output goes to a server. Other than that it is virtually no different from a regular Java technology-enabled program. Think of a servlet as an application, but one that (like an applet) requires a context in which to run, namely web server software. Servlets are used like CGI scripts, but take much less processor resources, and they allow the server end to be written in the Java programming language as well as the client. There is a page with much servlet information at: http://www.frontiernet.net/~imaging/servlets_intro.html
There is a servlet tutorial at http://java.sun.com/docs/books/tutorial/servlets/index.html
and another servlet tutorial at http://www.novocode.com/doc/servlet-essentials/
There is a servlet FAQ at http://www.saint-elie.com/

The web server starts up a servlet when the URL is referenced, and now your applets have something that they can talk to (via sockets) on the server that can write files, open connections to other servers, or whatever.
There is also a software technology from IBM called an "Aglet".
An aglet is a mobile agent that can go from machine to machine, performing tasks, serializing data collected, and "shipping itself" (code and data) to the next machine. It's too early to say if aglets are a flash in the pan or a dawning technology. Read about aglets at http://www.trl.ibm.co.jp/aglets/
Finally, there is the ticklet (Tcl/Tk) plugin for your browser (Netscape or Explorer) available at http://sunscript.sun.com/plugin/
Don't confuse Sun's JWS "Java Web Server" with JWS "Java Workshop SM". Java Web Server supports servlets, as does the lightweight and free server at Acme.com: http://www.acme.com/java/software/Acme.Serve.Serve.html

  1. (Sect. 13) My applet works on my machine, but fails when I put it on our web server. Why?

*It could be one of several reasons, and unfortunately the messages that you get in this situation aren't much help. In general, you can assume that either your applet's class files are corrupted somehow, or the web server can't find one or more of them when the browser needs them.
Be careful of the following things:

  1. (Sect. 13) How do I load a webpage using an applet?

*Use code like this,

getAppletContext().showDocument(
               new URL("http://www.here.com") );

Or, to show the page in another window or frame,

getAppletContext().showDocument(
        new URL("http://www.here.com"), "windowname" );
  1. (Sect. 13) How do I use an image as the background to my applet? How do I set the background color of my applet the same as the browser?

*You can simply do a g.drawImage(yourImage, x, y, this) in the paint() routine of your applet. If the image isn't big enough to fill the entire background, tile it or scale it. Here is some code to tile it

    // The background image is named "bg".
    int w = 0, h = 0;
    while (w < size().width) {
        g.drawImage(bg, w, h, this);
        while ((h + bg.getHeight(this)) < size().height) {
            h += bg.getHeight(this);
            g.drawImage(bg, w, h, this);
        }
        h = 0;
        w += bg.getWidth(this);
    }

Alternatively, the AWT can scale your background image to the size of the applet. The result quality will depend on the kind of image. Inside an applet class, you can use:

   drawImage(img, 0, 0, size().width, size().height, this);

You can set the background color to match the background color of the browser by passing the value in as a parameter, like this:

In the HTML applet tag:

<param name=BrowserColor value=F1F1F1>
(value should be the same hex as the HTML COLOR value).

In the Applet init() method:

    String colparam = getParameter("BrowserColor");



    int col = Integer.valueOf(colparam,16).intValue();



    setBackground( new Color(col) );

An applet cannot override the size imposed by the HTML. If you make the applet larger, the browser will still clip to the original size. If you need more room, open up a new Frame, Window or Dialog to show your output.

  1. (Sect. 13) How do you make the applet's background transparent?

*There is no way to give an applet a transparent background that lets the web browser background show through. You can simulate it by giving the applet a background that matches the underlying browser background. (For a straight color, it will be the value of <BODY BGCOLOR=nnnnnn> in the HTML file). It doesn't produce satisfactory results with a patterned background because of problems aligning the edges.
Lightweight components (new in JDK 1.1) have a transparent background, but that merely allows other components to show through. A lightweight component is always ultimately positioned in a heavyweight component.

  1. (Sect. 13) How do you do file I/O from an applet?

*Unsigned applets are simply not allowed to read or write files on the local file system (see answer to question 7.8).

Unsigned applets can, however, read (but not write) non-class files bundled with your applet on the server, called resource files.

See answer to question 7.8 and question 7.9.

  1. (Sect. 13) How do I pull a non-class file, such as a .gif, out of a jar file?

*[Question has been retired, in favor of question Q7.9] But note the BUG listed for JDK 1.2.2 at http://developer.java.sun.com/developer/bugParade/bugs/4251549.html

  1. (Sect. 13) How do I read a text file stored in a Jar?

*[Question has been retired in favor of Q7.9]

  1. (Sect. 13) How do you get a Menubar/Menu in an applet?

*In your applet's init() method, create a Frame instance and then attach the Menus, Menubar etc to that frame. You cannot attach the Menu or a Menubar to an applet directly.
Or get the parent Frame like this (doesn't work in all execution environments):

    Container parent = getParent();



    while (! (parent instanceof Frame) )



        parent = parent.getParent();



    Frame theFrame = (Frame) parent;

This second suggestion definitely doesn't work in the appletviewer, and probably won't work on Macs (where would the Menubar go?) or in some browsers. In JDK 1.1, just use a popup menu, which isn't attached to a Frame.

  1. (Sect. 13) Can I get rid of the message "Warning:Applet Window" along the bottom of my popup windows in my Applet?

*This is a security feature that prevents the applet programmer from popping up a window that looks like it came from the native OS and asking for passwords or credit card info (etc.). Users must always be aware of when they are talking to an unsigned applet. You can get rid of it by signing the applet, if the user accepts signed applets from you. In Netscape (only), using the Capabilities API to make the call

   PrivilegeManager.enablePrivilege("UniversalTopLevelWindow");

before creating the Frame eliminates the message, if the security manager passes it.

  1. (Sect. 13) When I subclass Applet, why should I put setup code in the init() method? Why not just a constructor for my class?

*The browser invokes your constructor, then setStub, then init(). Hence when your constructor is invoked, the AppletStub (and through it the AppletContext) is not yet available. Although in principle you can do things in the constructor that don't rely (even indirectly) on the AppletStub or AppletContext, it is less error-prone to simply defer all setup to the init() method. That way you know that anything that needs the stub/context will have it available.

  1. (Sect. 13) I want to know about {applets,applications} but the lousy book I got just talks about {applications,applets}. What can I do?

*The truth is that 95% of the material is the same, whichever your book chooses to focus on. Some people write their apps to work completely in a Panel, then depending on whether they're running stand-alone or in a browser the Panel is either added to a Frame or an Applet. The trick is that you need to add a listener to the application's Frame to handle the WINDOW_CLOSING (previously WINDOW_DESTROY) event yourself.
If you fail to do this, when running as an application, the window won't close. See Question 15.7 for a sample of the right handler.
In this scenario the following code will tell you which environment you're running in:

   public boolean isRunningInBrowser() {



        Component p = getParent();



        while(p != null && !(p instanceof Frame)) {



            p = p.getParent();



        }



        return (p == null);



    }
  1. (Sect. 13) How do I print a page with an applet?

*Browsers are starting to introduce support for this. Until they all have it, your best bet is to print a screendump. Using the browser to print the page may leave a blank where the applet is. Putting print support in the applet will print the applet only, not the rest of the browser page.
Also in the FAQ: Q5.2.

  1. (Sect. 13) How can I position my dialogs centered (not top left)?

*Use some code like this:

    void center(Component parent) {



        pack();



        Point p = parent.getLocation();



        Dimension d = parent.getSize();



        Dimension s = getSize();



        p.translate((d.width - s.width) / 2, (d.height - s.height) / 2);



        setLocation(p);



    }
  1. (Sect. 13) How can I get two applets on the same page to communicate with each other?

*This is the purpose of the InfoBus protocol. See http://java.sun.com/beans/infobus/index.html

The older way to do it was as follows. In your HTML page, give a NAME in the APPLET tag for the applet receiving the message, say <APPLET ... NAME=someName ...>. In the Java code of the other applet do

    Applet anotherApplet = getAppletContext.getApplet("someName");



Cast anotherApplet to the correct applet subclass, and you can call any methods in the applet subclass. Don't forget to use appropriate synchronization when two threads tweak variables. This only works when the applets are truly on the same page. If they are in different frames, it doesn't work.
You can walk through all the applets on an HTML page using code like that below. However this appears to be broken in Communicator 4.04 on Win95.

 



Applet otherApplet;



AppletContext ac =getAppletContext;



Enumeration applets = null;



for (applets=ac.getApplets(); applets.hasMoreElements(); ) {



    otherApplet=(Applet)applets.nextElement();



    if (otherApplet!=this) break;



    // do something with otherApplet, e.g. 



    // if (otherApplet instanceof FooApplet) ...



}

Some people suggest using the static members of a common class to communicate information between the applets. This is not recommended as it relies on class-loading behavior that may change in future. Netscape changed it in one Beta so it didn't work, then changed it back again so it did. It doesn't work if you use the "mayscript" tag though.
Inter-applet communication sometimes arises when you have a multi-screen type program and you don't want to force the user into downloading everything at once. One alternative is to make them into one applet with two GUIs. Try to avoid the need for applets to talk to each other. Also check the URL http://java.sun.com:81/products/hotjava/1.1/applet_environment.html which explains how it can be done in HotJava 1.1. Recommendation: avoid code which is browser-specific.

  1. (Sect. 13) How can I resize an applet?

*If you want resizing behavior from an applet, you should launch an external Frame that can be resized independently.
One programmer suggests using percentages for the height/width parameters in an applet tag, like this:

    <APPLET CODE="lewinsky.class" WIDTH="100%" HEIGHT="100%">
    

You can't resize the applet directly, but it does get resized when you resize the browser window (tested with Netscape 3.04 and 4.04, but does not work with appletviewer). If you have nothing else on your HTML page and use 100% for your width and height, the browser window looks almost like a real application.
For the extremely tricky: have the browser reload the page with the applet when the browser resizes using new values for width and height (probably not what you want most of the time). You would need Javascript to generate a page dynamically using document.write("...") when the browser resizes. Not recommended. Another possibility is to use the new SplitPane class in JFC.

  1. (Sect. 13) How do I sign an applet?

*The browser vendors have produced independent and different solutions for applet signature (alas). Here are some URLs on this topic.

See the Java Signing FAQ at http://www.fastlane.net/~tlandry/javafaq.txt

Read the basics of signing at: http://www.javareport.com/html/features/archive/9802/somers.shtml
Be aware that the mechanism of signing and administering signed code changed significantly between Java 1.1 and Java 2.

Netscape signing:
http://developer.netscape.com/docs/manuals/signedobj/javadoc/netscape_security_Target.html
https://certs.netscape.com/client.html
http://developer.netscape.com/docs/manuals/signedobj/capabilities/contents.htm
http://developer.netscape.com/docs/manuals/signedobj/targets/contents.htm

Microsoft signing:
http://www.microsoft.com/java/security/secfaq.htm
http://www.microsoft.com/java/sdk/20/tools/signcode.htm


14. Multi-Media

  1. (Sect. 14) Are there any good Java Image libraries?

*From JDK 1.2 on use the standard extension Java Advanced Imaging API. It lets your Java technology-based programs read and write many graphics file formats (PNG, JPG, BMP, GIF, TIFF, etc).

  1. (Sect. 14) Why won't my audio file play?

*Java 1.1 and earlier releases use one audio format exclusively. The audio file must be in .au format, recorded at 8 KHz, mono, in mu-law encoding. If your audio clip is in a different format (e.g., .wav) or a different frequency it must be converted to the exact specifications above before Java can play it. Support for .wav and other formats is part of the Java Media Framework coming in JDK 1.2.
Search at http://www.yahoo.com for GoldWave for Win 95, sox for Unix and similar conversion utilities for other systems.
Other sites:

  1. (Sect. 14) How can I do video streaming?

*That is the purpose of StreamBean. See http://www.streambean.com/streambean/

  1. (Sect. 14) Does the Java programming language support animated GIFs?

*Java 1.0.2 and earlier releases use GIF and JPEG formats, and do not use the GIF89 animated GIF format. (An animated GIF is one that contains successive frames of an image, so when they are displayed in quick sequence the image appears to contain movement). When you display an animated GIF in Java 1.0.2, you will just get the first frame. There doesn't appear to be any easy way to get other frames from the image.
The advantage of an animated GIF file is that there is only one file to download, and it is simple to do simple animations. The advantage of programmatic control over individual frames is that you control the rate and order of displaying them.
Here's a surprise: JDK 1.1 supports the animated display of animated GIFs. For simple animations animated GIFs are a lot easier and lighter-weight than coding an animation explicitly.

  1. (Sect. 14) How do I create animated GIFs?

*Use GIFanimator from ULead (said to be the best) http://www.ulead.com/, or GIF Construction Set from Alchemy Mindworks

  1. (Sect. 14) How do I prevent animated GIFs from flashing while displaying?

*The problem is most likely that in your paint method you have

 



    g.drawImage(img, ix, iy, this);



    

You should change this to

 



    g.drawImage(img, ix, iy, getBackground(), this);



    

This will change all the transparent regions of the image to the background color before painting to the screen. If you paint transparent images directly to the screen they flicker.
If that does not solve it then check that imageUpdate is

public boolean imageUpdate(Image img, int flags, int x, int y,



              int width, int height) {



        if ((flags & (FRAMEBITS|ALLBITS))!= 0) repaint();



        return (flags & (ALLBITS|ABORT)) == 0;



} 



    

update is

 



    public void update(Graphics g) { paint(g); } 



    

If you have a background Image behind the partly transparent animated GIF you will have to double buffer. You can crop the backgound image so you won't have to double buffer the full app and waste too much memory.

  1. (Sect. 14) Does the Java programming language support transparent GIFs?

GIF89a images with a transparent background show up as transparent without further filtering. Animated GIFs and transparent GIFs both display correctly
Even better, you can fill the transparent pixels with a color (so they appear non-transparent). Just pass the fill color explicitly:

 



    drawImage(img, x, y, w, h, fillcolor, this);



    


Further, you can filter the pixels of an Image to turn any bits you wish transparent. However, the most you can do is reveal what is underneath the image. You cannot reveal what is underneath the applet (i.e. on the browser itself). By default applets have a plain grey background.

  1. (Sect. 14) How do I play video?

*Use the Java Media Framework Player API.
Other sites:

  1. (Sect. 14) How can I play *.au files from an application?

*A new static method was introduced in JDK1.2 in the class Applet:

 



    public final static AudioClip newAudioClip(URL url) {



    

The method turns a URL (pointing to an audio file) into an AudioClip. Since the method is static it can be used without any objects of class Applet needing to exist, e.g. in an application. Once you have an AudioClip, you can play it with:

 



    MyAudioClip.play();



    

The Java Media Framework provides a richer API for playing sounds in an application.
For code prior to JDK 1.2, you can use the AudioClip or AudioPlayer class in sun.audio http://www.javaworld.com/javaworld/javatips/jw-javatip24.html. If you do this your code is no longer 100% pure Java code, as it relies on a vendor library.

 



    import sun.audio.*;



    
 



    URL url; ...



    AudioStream audiostream = new AudioStream(url.openStream());



    AudioPlayer.player.start(audiostream);



    ...



    AudioPlayer.player.stop(audiostream);



    

Also in the FAQ:
Use the new Java Media Framework API, allowing a wide range of video and audio formats to be played back. See previous question.

  1. (Sect. 14) How do I read in an image file, in an application?

Use

 



    Image img = Toolkit.getDefaultToolkit().getImage(fname);



    
  1. (Sect. 14) When I initialize a component,I call MyComponent.getImage() to get its image. createImage() returns null! I know the image works elsewhere. What's wrong?

*A peer component needs to exist for your component before you can get its image. This is done by the method addNotify() (surely one of the most poorly named methods of all -- it doesn't mean "add a Notify". It means "Notify that the Component has been added to a Container". It tells the system, "you need to create the peer for this Component now"). addNotify will be called for you when you add your component to a container.
Note that most applications do not call addNotify() directly. It is called for you when you add the component to a container. If you have any code that requires peer resources, you can move it into a thread that is started from a conditional branch of the paint() or update() method. That way the peer will definitely exist when the code is executed.
A common reason for seeming to require peer resources in a constructor, or alternatively in the getPreferredSize() method, (which is also usually before the peer is created) is to measure the area required for your window, in terms of font and image sizes. Font sizes may be obtained by calling Toolkit.getDefaultToolkit().getFontMetrics(somefont). This does not require a peer. Image sizes may be obtained by waiting for the relevant Image to load from the ImageProducer by using an ImageObserver, or a MediaTracker (see 8.15), also without requiring a peer. See 15.4 for more discussion of this problem.
If you override addNotify(), don't forget to call super.addNotify() in your overriding version.

  1. (Sect. 14) How can I force a reload a fresh version of an image into my applet? My image file is changed periodically, and I want the applet to go and retrieve it, not cache it.

*You need to turn off caching for the URL.

 



URL url = null;



URLConnection con;



try {



 url = new URL(getDocumentBase(),"image.jpg");



 con = url.openConnection();



 con.setUseCaches(false);



} catch (MalformedURLException e1) {



       System.err.println(e1.getMessage());}



  catch (IOException e2) {



       System.err.println(e2.getMessage());}



Note: Some programmers have reported that it caches anyway, even if they do this. That is thought to be an issue with the proxy server or the protocol used by Java to control proxy caching. Nothing has been found that explains exactly how this cache control works. Some say it's an http issue and that it works differently with http 1.0 verses http 1.1.
One programmer reported that even after turning off caching and calling image.flush() before getImage(..), he was still seeing the same picture even though it had been changed on the server.
He worked out a solution: access the image via a cgi script that returned a URL. This redirects the browser, and he put in an Expires: header as well to force the reload. Painful and laborious, but it got the result.

  1. (Sect. 14) How can I save an Image file to disk in JPG or GIF format?

*

Also try the Java Image Management Interface (JIMI), which is free for non-commercial use. JIMI is a toolkit that lets your Java programs read and write many graphics file formats (PNG, JPG, BMP, GIF etc). JIMI is written in 100% Java, and best of all, it's a breeze to get started with. See http://www.activated.com/jimi.html

  1. (Sect. 14) What causes this problem:
15.$ appletviewer m.html



16.Premature end of JPEG file



17.sun.awt.image.Im...Exception: JPEG datastream contains no image



18.at sun.awt.image. ... .produceImage(JPEGImageDecoder.java:133)



19.at sun.awt.image.Inpu...mageSource.doFetch(



20.                              InputStreamImageSource.java:215)



21.at sun.awt.image.ImageFetcher.run(ImageFetcher.java:98)



*There's a known bug in early releases of the JDK which can cause the above failure when reading a JPEG across a slow connection. The failure only occurs if the JPEG contains a large application data block (APPn marker) - the problem is that the JPEG decoder is trying to skip over the APPn and failing if not all of the APPn has been received yet. The quoted error message is only one of several possible complaints, but they all stem from the same root.
Photoshop is the most common source of JPEGs containing oversize APPn blocks. In particular, if you allow Photoshop 4 to save a thumbnail (preview) in a JPEG, the thumbnail plumps up Photoshop's private APPn marker to several K, which is usually enough to cause this problem.
There are several possible workarounds:

Any large overhead marker will cause the same problem; 4K of comment text, say, in a COM marker. So Photoshop is not the only source of tickling this bug.

  1. (Sect. 14) How can I convert between GIF and JPEG formats?

*In a word: don't.
There's hardly any overlap between the set of images that JPEG works well on and the set that GIF works well on. Sometimes, with enough care, you can get an acceptable conversion...but most of the time GIF<->JPEG conversion will just turn your image to mush. It's better to pick the right format in the first place.
Other sites:

  1. (Sect. 14) If you have an InputStream (rather than a file) that contains an Image, how can you display it?

*Use this method, and some adroit shuffling.

 



    Toolkit.getImage(URL url)



    

Create a thread that pretends to be an http server. Make it listen to some port (8765 for example) for incoming requests. When the thread gets a request, it should simply whisk up the appropriate http headers and follow it by the InputStream. Thus the component that has the input stream and wants to do the getImage(url) can now invoke:

 



    Toolkit.getImage("localhost:8765/")



    

The thread will act as a stream-to-url adapter, and send back the data It saves you from having to read 200K of JPEG data before you can begin drawing anything.

  1. (Sect. 14) How can I record sounds?

*The Java Media Framework will eventually support this, but it does not yet. JMF 1.0.1 only supports playback.
JMF 1.0.1 is bundled with JDK 1.2, and available as a separate download for JDK 1.1 and Netscape Communicator 4 with Java 1.1.
Other sites:

In the meantime, there is a package for Win95/NT available at http://www.scrawl.com/store/. It supports 8, 16-bit, stereo, mono, 11025, 22050, 44100 Hz record/play, load/save .WAV files. You could also interface to native code for your platform.

  1. (Sect. 14) Is there any built-in support for displaying HTML?

*JDK 1.1 supports rendering HTML using the unbundled JFC 1.1 package javax.swing. The Swing package is bundled in JDK 1.2. It has an elementary (graphics, tables, text) HTML bean that is good enough for simple rendering (help files, email, etc).
Other sites:

  1. (Sect. 14) I loaded an Image file from a JPEG/GIF file using the Toolkit/Applet.createImage(URL/String) method, and (the height and width are -1 / it will not draw to the screen). What is wrong?

*The behaviour of the AWT on creating images in this way is to do nothing at all.
When the image is first drawn using Component.drawImage(), or its size is requested, the image begins to load in a different Thread.
As the image loads, the ImageObserver specified in the drawImage()/getHeight() call is periodically notified of the loading status of the image, by calls to its imageUpdate() method.
In the case of Component.drawImage() call, the default behavior of Component.imageUpdate() is to schedule *another* repaint() call when the image has fully loaded. This means that, in particular the following code will not work:

 



    class MyComponent extends Component {



      ...



      public void paint(Graphics g) {



        ImageFilter cropper=new CropImageFilter(0,0,16,16);



        Image cropped_image=createImage(new



        FilteredImageSource(image.getSource(),cropper));



        g.drawImage(image,10,400,this);        // this line works



         // this line doesn't -



        g.drawImage(cropped_image,400,15,this);    



        }



      }



    

The cropped_image will not be created in time to be painted, and when it is finally created, another call will be scheduled to paint, which will try to draw another one, etc.
(Note also that creating objects like this in paint() methods is generally a very poor idea, since they are called very frequently, and you will strongly offend the garbage collector.
In order to get round this problem, you may i) add all such Images to a MediaTracker, and call the waitForAll() method. ii) implement your own ImageObserver interface, and wait for the imageUpdate() method to be called with the ALLBITS/FRAMEBITS value. i) is easier, but ii) is recommended, since there are reports of MediaTracker not working in some environments.
Also in the FAQ:

  1. (Sect. 14) How can I record sound in an applet?

*If you are using win95/nt, you could use SoundBite - Audio Recording in Applets. See http://www.scrawl.com/store/
It provides easy access to audio data in arrays:
short[] left, right;

  1. (Sect. 14) Is there support for PNG? Yes. PNG - Portable Network Graphics - provides a patent-free replacement for GIF and TIFF. If you save a GIF, don't forget to pay the royalty to Unisys - see Unisys's web page at http://www.unisys.com/LeadStory/lzwfaq.html. That patent is why GIFs are a poor choice for internet images.

The PNG format is specified in RFCs 1950, 1951, and 2083, and is unencumbered by licenses or patents. See also the PNG-1.1 specification at ftp://swrinde.nde.swri.edu/pub/png/documents.

The PNG format is supported by the Java Advanced Imaging API which is part of the 1.2 media APIs.