GUI abstract windows toolkit swing GUI Graphical User Interface let user enter data for application let user control processing steps display a view of data to user Graphical User Interface Mostly or entirely made up using instances of concrete classes provided in a graphics library Window class (Frame, JFrame in Java packages) subregions (Panel, JPanel in Java packages, positioning using layout managers ) controls (scrollbars, radio-buttons, check-boxes, action-buttons, popup-menus, ) input fields (textfield) rich display formats (e.g. javax.swing has styled text, html text, tables, views of tree structures, ) Limited use of an application defined subclass of some system class, used to render picture of application data GUIs: the problems Windows and graphics had been a major problem for developers of applications that ran on multiple platforms. Some concepts are common to all systems, but implementation mechanisms vary substantially. Typically graphics/windowing code got interwoven into application; major rewrite needed for reimplementation on alternative platform. Common concepts Window hierarchy framewindow communicates with OS s window manager subwindows Specialised controls usually (but not always) subwindows button, checkbox, radio cluster, scrollbar, Graphics environment associated with each window Menu-bar with drop down menus Different implementations Windows Mac only the main window was known to OS PC subwindows within main frame window Unix even things like thumb and arrows of scroll bar can be separate windows Controls slightly different functionality, eg scroll bars with/without proportional thumbs Graphics PC graphics context, Unix-X Graphics, and Macintosh Port have similar roles but differ in properties and associated function libraries
AWT objectives 1996 Java AWT Graphics that will run everywhere! Platform independent application code write once, run anywhere Support look and feel of each platform write once, debug everywhere? AWT Define Java window classes limited, lowest common denominator of different target platforms Write applications that work in terms of these classes Objects that are instances of these classes are essentially proxies - they interface to actual worker objects that are platform specific. Java Button Radio Checkbox created and used in your Java application in Java code AWT peer classes Button Mac Radio Button Checkbox Radio PC Button Checkbox Radio Checkbox Unix created and used by the C code of the JVM AWT peer classes java.awt.peer defines a set of interfaces public abstract interface ButtonPeer extends ComponentPeer { public abstract void setlabel(string label); Each platform s run-time system defines a set of component classes that implement the appropriate interfaces Mac s button uses Quickdraw button PC s button uses Window s button X s button uses Motif or OpenLook button AWT peer classes Instance of java.awt classes created along with instances of peer classes with which to work Runtimes for individual platforms include a component factory object (the Toolkit object) that has createbutton(), createcanvas(), createcheckbox(), This run-time object creates the local version of button (or whatever other element was needed)
AWT & peers Peer mechanism provides required look and feel platform independence for rest of code Imperfect variation of functionality for standard GUI components on different platforms makes total work alike very difficult to achieve Swing! Different approach, less reliant on underlying OS. Essentially Swing asks OS for single window area Swing then takes total responsibility for window (does not take advantage of any ability that OS may have for rendering and handling events for subwindows) Swing Get low-level details of events on its single window, sort out which conceptual subwindow (button, scrollbar, whatever) was involved, create Java event for that subwindow Get full access to entire window when drawing, draw buttons and other controls in accord with user preferences Swing visual styles Swing can draw controls in different styles Default styles mimic appearance of controls on host platform Can set user preferences to specify desired style Swing caution Swing GUI elements should only be accessed via the thread supplied by the GUI package. So? Swing thread issue Usually this is not a problem. Mainline thread constructs interface. Mainline thread shows interface. Subsequently, swing GUI elements are automatically accessed via GUI thread. But, sometimes, Dynamic swing interface Sometimes things are more dynamic construct part of interface, display it, add more elements later (can happen in JApplets when building interface in JApplet.init()) Then Can be problems
Dynamic interface thread collision Sometimes (not when you are testing your code, when the marker or your boss is trying it) get situation where GUI thread does update at same time as other thread tries to add an element to GUI Result possibly chaos possibly deadlock Fix SwingUtilities.invokeLater Ugly bits of code Code to build interface essentially defines a little runnable object that will make the changes that add (or remove) GUI elements. Reference to this thing passed in invokelater request to GUI framework. Code gets run by GUI thread; eliminating risk of deadlocks etc Ignore Swing problem for now Too convoluted to bother with in our simple exercises. See: http://java.sun.com/products/jfc/tsc/articles/thr eads/threads1.html NetBeans will help you build a safe swing interface Graphics object When you really need to draw a picture! Graphics object Graphics object encapsulates details of drawing environment for a window public abstract class Graphics extends Object { public abstract void clearrect(int x, int y, int width, int height); Concrete Graphics subclasses defined on individual platforms Graphics Different platforms do share similar coordinate models use pixel coordinates for drawing to screen (printer driver will deal with changes in resolution) (0,0) is top left corner, x increases to right, y increased down similar range of functions draw: lines, outlines of rectangles and ovals, filled rectangles and ovals, outline and solid arcs, text strings similar (r, g, b) colour space Same for Swing and AWT
Graphics Functionality provided by Graphics object is less than typically available in native graphic APIs for various platforms eg can t specify line thickness (even though all platforms do support such a concept) Graphics Graphics class defines methods draw drawarc(), drawbytes(), drawchars(), drawimage(), drawline(), drawoval(), drawpolygon(), drawstring(), drawrect(), drawroundrect() fill fillarc(), filloval(), fillpolygon(), fillrect(), set & get setcolor(), getcolor(), setfont(), getfont(), misc. cliprect(), clearrect(), copyarea(), setpaintmode(), Check the package interface on line documentation for function prototypes and full list of properties Graphics Related classes Font and FontMetrics Color Rectangle, Point, Polygon Image (and MediaTracker) Coord (0,0) Text in selected font Outlines (rect, oval, roundcornered rect) and line Output to browser status bar Color, Font and Graphics Polygon, filled rectangle, oval, and arc, rect3d Colours selected from palette Coord (400,450) Fonts Fonts are selected by name, size, and style create a new Font object as needed (typical sloppy Java programming, just forget about it when not needed; the garbage collector will tidy up for you) ffontname = ffontnames[n]; ffont = new Font(fFontName, Font.BOLD, 14); Fonts Java will have - Serif, SanSerif, Monospaced, Dialog, DialogInput Your system may have more, but if you are trying to be portable then you had better not rely on there being other Fonts. Size is point size Styles defined by Font constants FONT.BOLD, FONT.ITALIC, FONT.PLAIN Java can use Windows fonts, and there are lots installed by Windows OS; some fonts, in Windows format, are included in JRE
Colors Colors (Colours for those who spell in English) several different approaches to specifying colours) red, green, blue hue, saturation, brightness luminance and two chrominance computer terminals usually employ rgb Create Color objects as needed, specify rgb values (each in range 0255) - fcolor = new Color(135, 206, 235); // sky blue Colors Class Color has some predefined color constants black, blue, cyan, darkgray, gray, green, lightgray, magenta, orange, pink, red, white, yellow SystemColor class has colors used by default for things like color of window frame, border color for caption text, Colors There are several hundred standard colors (eg palette defined for Xlib, but not provided as inherent part of Java libraries) Standard colours, defined by rgb values (see /usr/openwin/lib/rgb.txt on Unix) 255 235 205 blanched almond 255 228 196 bisque 255 218 185 peach puff 255 222 173 navajo white GraphicsDemo Trivial applet, <HTML><TITLE>A Graphic Demo</TITLE> <BODY> <APPLET ALIGN=MIDDLE CODE="GraphicDemo.class" WIDTH=400 HEIGHT=350> </APPLET></BODY></HTML> GraphicDemo extends Applet impements Runnable this one has a thread that every second redraws the image using a different colour and font GraphicsDemo Using a separate thread (locus of control) Main thread just sitting in code that handles user interaction, updates of screen etc Second thread in loop with following form pick next colour pick next font force a repaint sleep for two seconds import java.awt.*; import java.applet.*; public class GraphicDemo extends Applet implements Runnable { public void paint(graphics g) { public void run() { public void start() { public void stop() { public void init() { private String[] fmessagelist = { "Hello World", "Hi mom", "Buy now", "Fresh Java", "Write once, run everywhere", "Hype", "WWW rules OK" ; private String[] ffontnames = { "SansSerif", "Serif", "Monospaced", "Dialog" ; // Color palette names and matching r, g, b values
public class GraphicDemo extends Applet implements Runnable { // Color palette names and matching r, g, b values private String[] fcolorpalette = { "lemon chiffon",, "rosy brown", ; private int fr[] = { 255,, 188, ; private int fg[] = { 250,, 143, ; private int fb[] = { 205,, 143, ; // private data members public class GraphicDemo extends Applet implements Runnable { // private data members private String fmessage; private Color fcolor; private String fcolorname; private Font ffont; private String ffontname; private Thread fthread; private boolean frunning; private Polygon fpoly; public void paint(graphics g) { if(!frunning) return; // watch out for initial drawing g.setfont(ffont); g.setcolor(fcolor); g.drawstring(fmessage, 40, 50); g.drawstring(ffontname, 40, 80); g.drawstring(fcolorname, 40, 110); g.setcolor(color.black); g.drawrect(10, 5, 25, 30); g.drawroundrect(20, 130, 100, 40, 8, 8); g.drawroundrect(20, 180, 100, 40, 16, 16); g.drawoval(150, 130, 40, 40); g.setcolor(fcolor); g.fillrect(210, 130, 25, 19); g.filloval(210, 150, 30, 80); Parameters control curvature of corners public void paint(graphics g) { g.filloval(210, 150, 30, 80); Initial & size g.drawline(5, 190, 300, 100); arc angles g.fillarc(160, 210, 50, 50, 15, 170); Bounding box if(math.random()>0.5) g.drawpolygon(fpoly); else g.fillpolygon(fpoly); if(math.random()<0.5) g.draw3drect(260, 260, 40, 30, Math.random() > 0.5); else g.fill3drect(260, 260, 40, 30, Math.random() > 0.5); Text in selected font Outlines (rect, oval, roundcornered rect) and line Output to browser status bar Color, Font and Graphics Polygon, filled rectangle, oval, and arc, rect3d Colours selected from palette public void start() { fthread = new Thread(this); fthread.start(); public void stop() { fthread.stop(); public void init() { frunning = false; fpoly = new Polygon(); fpoly.addpoint(210,10); fpoly.addpoint(208, 72);
public void run() { for(int i=0;i<50;i++) { int n; showstatus("loop " + i); n = i % fmessagelist.length; fmessage = fmessagelist[n]; n = i % ffontnames.length; ffontname = ffontnames[n]; ffont = new Font(fFontName, Font.BOLD, 14); n = i % fcolorpalette.length; fcolorname = fcolorpalette[n]; fcolor = new Color(fR[n], fg[n], fb[n]); frunning = true; repaint(); try { Thread.sleep(2000); catch (InterruptedException ie) { FontMetrics Unlikely to need to use this class in routine graphics displays. Use Font.getFontMetrics() to get FontMetrics object for chosen font. FontMetrics object can then provide detailed information relating to length of a String (displayed in that Font) height of a character position (to text base-line) of top/bottom of character FontMetrics Used mainly with relatively complex text passages where you need text in different fonts, sizes, and styles. Such text gets output as several strings, each with specified font settings. Need to know position of end of one piece of text before can position next piece. FontMetrics Font myfont = new Font( Serif, Font.BOLD, 32); FontMetrics measure = new FontMetrics(myFont); int spacewidth = measure.stringwidth( ); int height = 50; int pos = left; g.drawstring(s1, pos, height); pos = pos + spacewidth + measure.stringwidth(s1); int len2 = measure.stringwidth(s2); if(pos + len2 > limit) { pos = left; height+= vspace; g.drawstring(s2, pos, height); FontMetrics Positioning of text can be more elaborate varying line spacing to suit text etc. baseline, height, ascent, descent, leading, This is text with some odd characters like and fififl,, Ç, T, g,,, pq  And more ζ ξ p A Use swing if you need fancy text You can do your own fancy text output using FontMetrics but, if you are just displaying text (and not some complex mixture of text and other graphics), you will find it much easier to use a styled text output class from the swing libraries
Images Images gif or jpeg pictures loaded from file (local, or accessed via network) Image can be drawn in original size, or you can specify size and system will scale image for you Graphics.drawImage(Image, int x, int y, ImageObserver) Graphics.drawImage(Image, int x, int y, int width, int height, ImageObserver) Images Oddity getimage() doesn t get an Image! It starts the process of fetching image then returns (bytes for image may take some time to arrive across net) Code has to deal with this behaviour ImageObserver gets called regularly as data arrive, can then repaint a bit at a time MediaTracker can be set to delay main thread until data are complete Watching images load MediaTracker Originally, I had a little demonstration at this point that showed a picture being loaded You could actually see successive lines of the image being drawn Networks and computers are so fast these days that the demo no longer works! The picture appears instantaneously. Still have to use ImageObservers Still have to use MediaTrackers Often best approach is to load all images during program initialization, using a MediaTracker to make program wait until all are loaded Create a MediaTracker to work with the ImageObserver object that is loading. Give MediaTracker a reference to each of the images that it is to monitor associate an ID with each ID can act as a priority (lower numbered IDs should get dealt with first) Tell MediaTracker to delay until specified Image has arrived (or delay until all arrived) MediaTracker public void init(){ String picture = getparameter("picture"); if(picture == null) return; fimage = getimage(getdocumentbase(), picture); MediaTracker waitforit = new MediaTracker(this); waitforit.addimage(fimage, 1); try { waitforit.waitforid(1); catch (InterruptedException ie) { Code fragment from an Applet this references the Applet, which is an ImageObserver Superimposing images --- animations etc Typically, an animation (e.g. a computer game) will have irregularly shaped objects moving across a fixed background. Images typically are defined by rectangles. Don t want a blacked out rectangle surrounding each game piece.
Superimposing images --- animations etc Graphics systems allow you to avoid this by defining not just red, green, blue values of each pixel but also transparency If a pixel is completely transparent, you see the colour of any background pixel. If pixel is completely opaque, you see its r,g,b colour Otherwise you see some mixture of colours Superimposing images --- animations etc The transparency is the alpha channel of a pixel red, green, blue, alpha It is possible to adjust an Image in your Java code create a PixelGrabber from your Image make vectors of r,g,b and a values (each horizontal scanline appends to vector), fill using PixelGrabber you adjust alpha values of chosen pixels you create a new Image using modified array Superimposing images --- animations etc Often easier to use one of tools that works with gif files and defines a (single) chosen colour as being transparent. Picture supposedly represents leaping frog (it is a 32x32 block, blacked out, then picture drawn in a paint program) Superimposing images --- animations etc Frog can now be imposed on any background picture + = Define black as transparent (this will be an option in a gif manipulation program) This demo doesn t work in all browsers (it should though). HTML for Animation <HTML> <TITLE>A simple animation/transparent gif demo</title> <BODY> <APPLET ALIGN=MIDDLE CODE="AnimDemo.class" WIDTH=400 HEIGHT=350> <PARAM NAME="actor" VALUE="./images/frog.GIF"> <PARAM NAME="bkgd" VALUE= "./images/background.gif"> </APPLET> </BODY></HTML> Animation Load background and moving image(s) (sprite) Wait till both loaded Create thread Run thread move sprite (here just has approximate sine wave to define motion) force repaint sleep
Animation Need to do own clipping - don t want sprite to appear outside of background image Flicker? use double buffering scheme if do have flicker problems Continuous motion? aim for about 24 repaints per second and small motions import java.awt.*; import java.applet.*; public class AnimDemo extends Applet implements Runnable { public void paint(graphics g) { public void start() { public void stop() { public void run() { public void init() { // private data public void start() { fthread = new Thread(this); fthread.start(); public void stop() { fthread.stop(); public void run(){ for(;;) { dx += deltax; if(fx+dx > getsize().width) dx = 0; dy += deltay; if(dy <= -32) deltay = 8; else if(dy >= 16) deltay =- 8; repaint(); try { Thread.sleep(500); catch (InterruptedException ie) { Move frog across full width of Applet s window (maybe wider than background). Position defined by dx, dy offsets to start point; limited ranges defined. Two frames per second. public void init() { String picfilename = getparameter("actor"); factor = getimage(getdocumentbase(), picfilename); picfilename = getparameter("bkgd"); fbackground = getimage(getdocumentbase(), picfilename); MediaTracker waiter = new MediaTracker(this); waiter.addimage(factor,1); waiter.addimage(fbackground, 2); try { waiter.waitforall(); catch (InterruptedException ie) { fx = -32; fy = 48; dx = dy = 0; deltax = 8; deltay = -8; public void paint(graphics g){ g.cliprect(0, 0, fbackground.getwidth(this), fbackground.getheight(this)); g.drawimage(fbackground, 0, 0, this); g.drawimage(factor, fx+dx, fy+dy, this); Animations Typical animation would use set of slightly different images Each repaint operation would change to next image from sequence Synchronisation mechanisms may be needed one thread will be updating record of where program has reached in sequence other thread may be trying to use image
Animations Part of new Media API sprites images that move across the background scripting specify how sprites get created/removed move change through sequence of images interact Subwindow for drawing Where to draw? Those examples simply output to the applet s main window (equivalent for an application would be drawing on Frame ) Generally, main window or frame has to hold many different controls, output regions etc. Most programs will use a Canvas subclass for graphic output - Canvas simply defines a drawing area occupying some part of enclosing window you subclass Canvas to provide an effective paint() function MyCanvas extends Canvas MyCanvas owns connection to data object (model in model-view-control); data object has reciprocal link back to MyCanvas has size set gets told to paint(), relays request to data object Associated data object when changed, invokes repaint() on associated MyCanvas awt and swing again AWT designers thinking of frame some standard controls Canvas where draw application specific data Swing different view, most Java is used in enterprise (business) computing, need is for lots of displays of text in tables etc frame standard control fancy text outputs No provision for drawing application specific data No Canvas in swing Swing omits canvas Can use JPanel some issues about setting size (a Panel, or JPanel, is a container for other components; it recomputes its size when overall window size changed; it recomputes its size by asking the components it contains for their sizes; JPanels with no components can get zero size!) Don t mix swing and awt
User interface User interface Most of user interface made up from library supplied classes controls input fields Canvas (or javax.swing.jpanel) displaying application data would only be a limited part (and may not be needed at all if application is conventional business data processing one with form entry and tabular results displays) User interface Typical user interface has main window with multiple subwindows output subwindows scrollable text, canvas for graphics, data input text input field, canvas again (can pick up mouse clicks and have program interpret as drawing action) control checkboxes, action buttons, radio selection, scroll bars, menus, Interface design placing elements within window Layout managers How can you arrange subwindows? Traditionally, programmers used absolute coordinates and sizes. This did not suit AWT size of a checkbox (and almost every other control) would differ from one platform to another area occupied by text strings, bounding boxes etc vary An arrangement that looked fine on one platform might be unusable on another. Layout managers Somewhat similar problems had been encountered earlier with the Xlib- libraries for graphics outputs on Unix systems. There solution had been for programmers to surrender (to code provided with the library) some the fine control of arrangement of components. AWT adopted this approach (swing follows, adds a few more layout managers)
Layout managers When building interface (awt or swing) you choose one of a small number of standard arrangements for subwindows you create a layout manager object - an instance of a class that keeps track of subwindows and their (minimum) sizes chooses how to position them in the enclosing window you associate this layout manager with the window It is possible to specify that you do not want to employ a layout manager, and position subwindows yourself. Generally regarded as hacking. Layout managers The different Window classes (Frame, Panel/Applet etc) have default layout managers. layout manager actually associated with container level in class hierarchy (superclass to window) Container has setlayout(layoutmanager m) add(component c) add(component c, constraints) Canvas Flowlayout No Yes Maybe Frame with a FlowLayout manager BorderLayout Add components specifying region names as constraints (forgot the name? put in center) North components rearrange if user resizes Frame Canvas No W e s t Center E a s t Yes Maybe South Advanced Layouts GridLayout (illustrated later in calculator example) n x m array of slots for components successive add() operations fill out rows CardLayout (not illustrated) displays one component from a set, functions like first(), next(), previous(), last(), to cycle through components Advanced Layouts GridBagLayout (illustrated later in dialog example) complicated layouts, best used in conjunction with an interface builder tool grid of cells, but individual components can occupy different number of cells
GridBagLayout Component is added to container along with a GridBagConstraints object GridBagConstraints specifies number of grid cells allocated to component (gridwidth, gridheight constraint properties) position of component within its area defined (achor property) fill property (does component resize to fit display area horizontally, vertically, or both) padding around components (insets and ipadx, ipady) how display areas resize if enclosing window changes GridBagConstraint x =0, y =0 width = 1, height =2 GridBagConstraint x =0, y =2 width = 3, height =1 GridBagConstraint x =3, y =0 width = 2, height =3 Swing and layouts Swing shares all AWT s standard layouts Swing defines a few additional ones e.g. BoxLayout Better than JPanel (or AWT Panel) for grouping several components and arranging them (vertically or horizontally) others like SpringLayout, ViewPortLayout see Sun s examples for use Create your user interface Creating your user interface Development environment (eg NetBeans) may provide an editing tool that helps you arrange parts of your interface If you don t have an editing tool, or you want more control, you will need to compose the code that builds your interface create components, place within layout managers Be aware of restrictions Container may only allow one component Each of areas, North Center can be empty or hold one nested component W e s t North Center E a s t South Create your user interface Create your user interface
Use nested containers Use nested containers W e s t North Center E a s t W e s t North Center E a s t Overall frame with BorderLayout South You want two labelled buttons here (4 components)? Have to add a nested Panel (JPanel) container Added Panel (JPanel) South Controls added to Panel (which has FlowLayout) (J)Label (J)Button (J)Label (J)Button Create your user interface Create your user interface Creating your user interface There is a nesting hierarchy you choose a layout for top-level frame you place a Panel as one of components in this frame, (occupying one of positions in its slots as defined by chosen layout manager) you select a layout for the Panel you place other components inside Panel This allows complex interfaces with large output areas, arrays (palettes) of controls, status information lines etc Creating your user interface Events from controls you handle your controls by attaching listeners to them when you create them Create your user interface Create your user interface Only listener for events you want to handle Things like textboxes, scrollbars, checkboxes etc generate events for every change. Rare for your application to need to be aware of these changes A text box will look after all editing operations without your intervention. Typically you only want final values Listen only to the ActionButtons when user clicks Do It Now button, your application interrogates text boxes, checkboxes, scrollbars etc for chosen values So, creating an interface Create your user interface Create your user interface
Two issues to consider Needs of your application GUI s role Input of data Controls on processing Output of results What are you inputs? What processing controls do you need? What output data must you display? Building blocks available in GUI library GUI library Containers and simple components You start with one container The Window (Frame or JFrame class) You divide up area of window Area for input fields and controls Area for outputs Each such area has many components, so it must be represented by another container (Panel, JPanel, Box or other container used for subwindow) Create your user interface Create your user interface GUI interface first decisions Frame s area is split in areas Each area usually occupied by another container (Panel, whatever) Arrangement of areas in main Frame dictated by a layout manger GUI interface - next Your needs for input data and controls Select some processing option? Select from pop-up list? Select using check boxes? Text data input? Simple text input? Large area of text? Select file? Action button displays file dialog Start processing Action button Create your user interface Create your user interface Compose input & control elements Many input elements? Container (Panel) used for input elements must be given some layout manager Different input components must be selected to handle inputs required by application Input components must be added to container, layout manager given hints on layout Outputs What are the output data? Do you really have one output field or many? For each output field Can you use one of standard data display classes TextArea (possibly scrolling if a lot of text) Table Tree How can you arrange outputs Container again (Panel) Layout manager Create your user interface Create your user interface
Building blocks for interfaces Containers Container Panel Applet ScrollPane Window Dialog FileDialog Frame Containers AWT, javax.swing has JPanel, etc Containers Window A Window object is a top-level window with no borders and no menubar. Frame A Frame is a top-level window with title and border; default layout is BorderLayout. Dialog A window that takes input from the user. FileDialog Mimics standard modal file selection dialog as commonly used on platform. Panel Panel is the simplest container class. A panel provides space in which an application can attach any other component. The default layout manager for a Panel is FlowLayout. Component Button Canvas Checkbox Choice Label List Scrollbar TextComponent TextArea TextField Components AWT, javax.swing has JLabel, etc Components - Button Button owns two strings (label, action name; same by default) set/get Label(), ActionCommand() normal constructor sets both: Button(String s) addactionlistener() simple request for action by program (like earlier example where had North, East, buttons that moved figure that was displayed in Canvas)
class DataObject implements ActionListener { class MyCanvas extends Canvas { class Display implements WindowListener { public class EventDemo1 { public static void main(string args[]) { class DataObject { public void actionperformed(actionevent e) { String s = e.getactioncommand(); if(s.equals("north")) { fy0 -= 5; fcanvas.repaint(); else if(s.equals("west")) { fx0 -= 5; fcanvas.repaint(); class Display public Display(DataObject d) { fframe = new Frame(); fframe.setlayout(new FlowLayout()); fcanvas = new MyCanvas(d); d.linktocanvas(fcanvas); fframe.add(fcanvas); Button b; b = new Button("North"); b.addactionlistener(d); Component Button Canvas Checkbox Choice Label List Scrollbar TextComponent TextArea TextField Components Canvas Canvas (must be subclassed!) just a blank rectangular drawing area paint data objects trap mouse actions typically MyCanvas extends Canvas will add a pointer to some data object(s) that is(are) to be displayed, and will override paint() class MyCanvas extends Canvas { public MyCanvas(DataObject d) { fdata = d; setsize(400, 400); public void paint(graphics g) { fdata.paint(g); private DataObject fdata; Components Canvas Canvas used directly in program? You will see textbook examples where programmer creates Canvas gets Graphics object associated with Canvas arranges for data structure to draw on Graphics I don t think this is really correct it probably won t handle updates properly (eg when window hidden then re-exposed) - as simply get call to Canvas.paint() { violates normal convention of not drawing directly, instead notifying display of need for update then being asked to draw when display ready
No JCanvas? Swing doesn t include anything directly equivalent to Canvas have to subclass JPanel provide link to data object overwrite paint function mess around with setsize, setpreferredsize, and setminimumsize (JPanels aren t like Canvases, they try to recompute their sizes based on what they contain and have a habit of shrinking!) Component Button Canvas Checkbox Choice Label List Scrollbar TextComponent TextArea TextField Components - Checkbox Stopwatch example Checkbox handles two roles: ordinary check box (a choice that is either selected or not selected; selection independent of other choices) radio button (an instance of a mutually exclusive set of choices) Differentiate roles according to whether Checkbox has an associated CheckboxGroup BorderLayout BorderLayout Frame Frame East a Panel South a Panel FlowLayout FlowLayout
BorderLayout BorderLayout Frame Canvas East a Panel Frame Canvas East a Panel Two checkboxes Three buttons South a Panel South a Panel FlowLayout FlowLayout FlowLayout FlowLayout Stopwatch ( ComponentsDemo1 ) Illustrating border layout panels (with default flow layout) as subcomponents action buttons canvas mutual exclusion radio buttons in a CheckboxGroup also more Threads (to be explained in detail later) import java.awt.*; import java.awt.event.*; class StopWatch implements ActionListener, ItemListener, Runnable { class MyCanvas extends Canvas { class GUI implements WindowListener { public class ComponentsDemo1 { public static void main(string[] args) { StopWatch c = new StopWatch(); GUI g = new GUI(c); g.show(); ComponentsDemo1 : Application ComponentsDemo1 simply provides main() create principal objects get things run MyCanvas the usual, subclass Canvas to get something with effective paint() uses double buffered update() ComponentsDemo1 : Application GUI builds the interface create Frame (with default BorderLayout) create MyCanvas, places MyCanvas in center three action buttons, panel to hold buttons, places panel in south two Checkboxes, with CheckboxGroup, another panel to hold them, places panel in east and handles closing of window by termination application
ComponentsDemo1 : Application StopWatch handles actions involving stop, start, reset buttons changes to Analog / Digital choice items has internal thread suspended and resumed as needed while running does (sleep (1000/60), update ticks etc, maybe force repaint) draws clock in analog or digital form ComponentsDemo1 : Application StopWatch 60 ticks per second, 60 seconds per minute digital display as string, minutes:seconds, only updated every second analog display three hands updated at each tick 1000/60 16, don t expect it to keep perfect time Stopwatch example import java.awt.*; import java.awt.event.*; class StopWatch implements ActionListener, ItemListener, Runnable { class MyCanvas extends Canvas { class GUI implements WindowListener { public class ComponentsDemo1 { public static void main(string[] args) { StopWatch c = new StopWatch(); GUI g = new GUI(c); g.show(); class MyCanvas extends Canvas { public MyCanvas(StopWatch c) { fstopwatch = c; setsize(400, 400); public void paint(graphics g) { fstopwatch.paint(g); public void update(graphics g) { Graphics gr; if (foffscreenbuffer==null (! (foffscreenbuffer.getwidth(this) Make sure == this.getsize().width && foffscreenbuffer.getheight(this) have buffer == this.getsize().height))){ foffscreenbuffer = this.createimage( getsize().width,getsize().height); Use it copy gr = foffscreenbuffer.getgraphics(); gr.clearrect(0,0, getsize().width, getsize().height); paint(gr); g.drawimage(foffscreenbuffer, 0, 0, this); private Image foffscreenbuffer; private StopWatch fstopwatch; uses double buffering Offscreen buffer code Check whether have an offscreen buffer with the same dimensions as drawing area, if don t have one at all (or its size is wrong) then create offscreen buffer. Get a Graphics object associated with the offscreen buffer. Draw data using that Graphics. Copy completed image to screen
Double buffering why? Problem Your data is changed You must erase the existing display You must draw the new data The screen flickers irritating users. Only really an issue if you are composing a picture of your own data and you update this frequently; very rare to have to worry about it if your interface is entirely made up of standard awt/swing classes. Double buffering how? Create an image in memory one pixel (4 bytes in memory) for each pixel on screen Erase the in-memory image Draw into the in-memory image Paint to screen Result no flicker class GUI implements WindowListener { public void windowclosing(windowevent e) { System.exit(0); public void windowclosed(windowevent e) { public void windowiconified(windowevent e) { public void windowopened(windowevent e) { public void windowdeiconified(windowevent e) { public void windowactivated(windowevent e) { public void windowdeactivated(windowevent e) { WindowListener stuff as previously illustrated public GUI(StopWatch c) { public void show() { fframe.show(); private Frame fframe; private MyCanvas fcanvas; private StopWatch fstopwatch; public GUI(StopWatch c) { fstopwatch = c; fframe = new Frame(); Setting layout manager explicitly; didn t need to, BorderLayout is default for Frame fframe.setlayout(new BorderLayout()); fcanvas = new MyCanvas(c); c.linktocanvas(fcanvas); fframe.add(fcanvas, "Center"); Panel p = new Panel(); fframe.add(p,"south"); Button b; b = new Button("Start"); b.addactionlistener(c); p.add(b); b = new Button("Stop"); b.addactionlistener(c); p.add(b); b = new Button("Reset"); b.addactionlistener(c); p.add(b); fframe.setlayout(new BorderLayout()); ut Frame Canvas fcanvas = new MyCanvas(c); c.linktocanvas(fcanvas); fframe.add(fcanvas, "Center"); Panel p = new Panel(); fframe.add(p,"south"); Button b; b = new Button("Start"); South a Panel b.addactionlistener(c); p.add(b); GUI building code Start with a Frame (a Window with all the trimmings!) Set your layout manager Create the canvas class Add to the frame hint to layout manager, this goes in center Two Buttons each with Labels, need a Panel to group them Create labels and buttons, add to panel, listen to buttons Add Panel to south region
public GUI(StopWatch c) { b = new Button("Reset"); b.addactionlistener(c); p.add(b); p = new Panel(); fframe.add(p,"east"); CheckboxGroup grp = new CheckboxGroup(); Checkbox analog = new Checkbox("Analog", grp, false); Checkbox digital = new Checkbox("Digital", grp, true); p.add(analog); p.add(digital); analog.additemlistener(c); digital.additemlistener(c); fframe.pack(); fframe.addwindowlistener(this); Frame Canvas South a Panel p = new Panel(); fframe.add(p,"east"); East a Panel CheckboxGroup grp = new CheckboxGroup(); Checkbox analog = new Checkbox("Analog", grp, false); Checkbox digital = new Checkbox("Digital", grp, true); p.add(analog); p.add(digital); class StopWatch implements ActionListener, ItemListener, Runnable { public StopWatch() { public void LinkToCanvas(Canvas c) { fcanvas = c; private void DoStart() { private void DoStop() { private void DoReset() { public void paint(graphics g) { public void run() { public void itemstatechanged(itemevent e) { public void actionperformed(actionevent e) { Thread fthread; Canvas fcanvas; boolean fanalogstopwatch = false; boolean frunning = false; int fminutes, fseconds, fticks; public StopWatch(){ fcanvas = null; DoReset(); fthread = new Thread(this); fthread.start(); public void LinkToCanvas(Canvas c) { fcanvas = c; private void DoStart() { if(frunning) return; frunning = true; fthread.resume(); private void DoStop(){ if(!frunning) return; frunning = false; fthread.suspend(); private void DoReset(){ if(frunning) return; fminutes = fseconds = fticks = 0; if(fcanvas!= null) fcanvas.repaint(); public void paint(graphics g) { if(!fanalogstopwatch) { String time = "" + fminutes + ":" + fseconds; g.drawstring(time,40,40); else { g.drawoval(20,20, 181, 181); double angle, armlength, x, y; armlength = 90; angle = 6.0*fTicks; angle = angle*math.pi/180.0; x = armlength*math.sin(angle); y = armlength*math.cos(angle); g.drawline(111,111, 111+(int)Math.round(x),111-(int)Math.round(y)); g.setcolor(color.blue); armlength = 70; angle = 6.0*fSeconds; g.setcolor(color.red); armlength = 50; angle = 6.0*fMinutes; g.setcolor(color.black); paint Either output string with digits Draw a clock face working out where the clock-hands should be for minutes, seconds etc
public void run() { fthread.suspend(); for(;;) { try { Thread.sleep(16); catch (InterruptedException ie) { fticks++; if(fticks == 60) { fticks = 0; fseconds++; if(fseconds == 60) { fseconds = 0; fminutes++; if(fanalogstopwatch) fcanvas.repaint(); else if(fticks == 0) fcanvas.repaint(); Thread (More on threads soon) Here Forever Sleep a bit Update time Request repaint of display public void actionperformed(actionevent e) { String s = e.getactioncommand(); if(s.equals("start")) DoStart(); else if(s.equals("stop")) DoStop(); else if(s.equals("reset")) DoReset(); public void itemstatechanged(itemevent e) { if(e.getstatechange() == ItemEvent.DESELECTED) return; String s = (String) e.getitem(); if(s.equals("analog")) fanalogstopwatch = true; else fanalogstopwatch = false; if(!frunning) fcanvas.repaint(); Will get double notification on change: deselect old, select new. Here only need to bother with the select new. Components - Checkbox; continued! Independent choice Checkboxes used in much the same way - just don t provide a CheckboxGroup. Arrange for an ItemListener that will deal with ItemEvents as these are generated by changes to individual Checkboxes. Component Button Canvas Checkbox Choice Label List Scrollbar TextComponent TextArea TextField
Components - Choice Choice is an alternative to having an interface involving a large set of radio buttons. Choice holds a set of items (Strings) displays as a form of pop-up menu only allows one item to be selected sends itemevents to ItemListener when selection changed (though usually easier to handle differently) can be asked for current selection Components - List List is a variation on Choice has a little scrolling subwindow showing some of possible choices (you select how many) permits multiple selections (mechanism depends on platform shift-click, control-click ) if single selection, can be asked for current selection if multiple selections permitted, can be asked to return array with Strings identifying items selected Components - Label Lists and Choices do not inherently possess any identifying information in display. Usual to employ Labels to identify them. Place Label and Choice (List) in a Panel. Label displays a non-editable string (can be changed by program) Example with labels, choices, lists Breakfast order dialog (like those printed lists you find in hotel rooms where you tick the items you want for breakfast) No real layout just a series of choices, lists, text inputs in a window with FlowLayout But trying to keep Label/Choice, Label/List etc together So do have extra Panel components to hold such pairs
Swing Applet using FlowLayout (action) Button Labels Choices (single item from pop-up menu) List => JList Choice => JComboBox (Some Microsofty person combo-box was the VisualBasic equivalent) List (multiple selection enabled, showing 3 items from range of 9) TextArea used for output (set to non-editable ) import java.awt.*; import java.awt.event.*; import java.applet.*; public class ComponentsDemo2 extends Applet implements ActionListener { public ComponentsDemo2() { public void actionperformed(actionevent e) { private Choice fchoice1; private Choice fchoice2; private List flist; private TextArea ftextoutput; public ComponentsDemo2() { add(new Label("Pick one item in choices, many in list")); Button b = new Button("Serve my meal"); add(b); b.addactionlistener(this); Panel p; p = new Panel(); add(p); p.add(new Label("First course")); Choice c; c = new Choice(); c.add("grapefruit"); c.add("orange juice"); c.add("melon"); Can define a default selection c.add("corn flakes"); c.select("corn flakes"); fchoice1 = c; p.add(c); Panel p; p = new Panel(); add(p); p.add(new Label("First course")); Choice c; c = new Choice(); p.add(c); Creating the elements Button Give it a label Add a listener Group : Label First course, Choice with options Create Panel to keep the two together Create Label with string, add to Panel Create choice, create string options in choice, add choice to Panel, add Panel to Applet
public ComponentsDemo2() { Specify number of choices displayed, & whether multi-selections allowed p = new Panel(); add(p); p.add(new Label("Cooked course")); List ll = new List(3, true); ll.add("boiled egg"); ll.add("toast"); ll.select(0); ll.select(8); flist = ll; p.add(ll); p = new Panel(); add(p); p.add(new Label("Beverage")); c = new Choice(); c.add("tea with lemon"); c.add("coffee"); c.select("coffee"); fchoice2 = c; p.add(c); ftextoutput = new TextArea("Breakfast: ",2, 60); ftextoutput.seteditable(false); add(ftextoutput); List & choice Generally similar in use Different appearance List has option of multiple selections Here Create List object (java.awt.list a GUI component, not List as in datastructures!) Add elements (strings for choices offered by list) Some can be marked as pre-selected Add to Panel etc public void actionperformed(actionevent e){ String s = e.getactioncommand(); if(!s.equals("serve my meal")) return; ftextoutput.append( fchoice1.getselecteditem()); ftextoutput.append(", "); String[] mains = flist.getselecteditems(); for(int i=0; i<mains.length;i++) { ftextoutput.append(mains[i]); ftextoutput.append(", "); ftextoutput.append( fchoice2.getselecteditem()); actionperformed Only one action button, so don t need to see what action requested. Read data from input fields. Use data to compose output. Display output text in TextArea ComponentsDemo2 example Approach illustrated is usually easiest have an action button to act when user has made choices have references to Choice & List components, ask for selections when needed Alternative implementation implements ItemListener - get events for each selection (and deselection) NetBeans GUI-editor style - AWT
NetBeans - awt NetBeans GUI editor - swing private void initcomponents() { label1 = new java.awt.label(); b = new java.awt.button(); panel1 = new java.awt.panel(); label2 = new java.awt.label(); c = new java.awt.choice(); c.add("grapefruit"); NetBeans swing Has extra component editors for things like tables, combo-boxes, lists Let you populate the control with a set of data Useful if set of options is fixed If generating content of control dynamically, tell NetBeans to Reset to default and use custom coding Component Button Canvas Checkbox Choice List Scrollbar TextComponent TextArea TextField Components - ScrollPane ScrollPane A container which implements automatic horizontal and/or vertical scrolling of a single child component. use create a ScrollPane create a canvas put canvas in ScrollPane Components - Scrollbar Scrollbar Allows user to select from a range of values Define as HORIZONTAL or VERTICAL Provide minimum, maximum (and initial value) Need an AdjustmentListener that will pick up changes to scroll setting
ComponentsDemo3 Applet to display a large image such as a map. Image displayed in a ScrollPane. Scrollbar used to provide zoom effect can scale basic image up or down ScrollPane adjusts to resized image Scrollbar used to change map s own scale Scrollbars belonging to ScrollPane (select position in map) Effects of scaling the map ComponentsDemo3 Simple Applet (implements AdjustmentListener) init() select BorderLayout, add a label load the image (wait for loading to complete, can be slow for large map) create MyCanvas, ScrollPane, and Scrollbar establish links amongst items adjustmentvaluechanged() get user selected value (range [19], 5=>standard size, 4 is half size, 3 is quarter size, 6 is double size etc) get MyCanvas to rescale import java.awt.*; import java.awt.event.*; import java.applet.*; class MyCanvas extends Canvas { public MyCanvas(Image i, ScrollPane s) { public void paint(graphics g) { public void setscale(int scl) { // private data public class ComponentsDemo3 extends Applet implements AdjustmentListener { public void init() { public void adjustmentvaluechanged(adjustmentevent e) { private MyCanvas fcanvas; public class ComponentsDemo3 extends Applet implements AdjustmentListener { public void init() { setlayout(new BorderLayout()); add(new Label("Map display", Label.CENTER), "North"); String picture = getparameter("picture"); if(picture == null) return; Image i = getimage(getdocumentbase(), picture); MediaTracker waitforit = new MediaTracker(this); waitforit.addimage(i, 1); try { waitforit.waitforid(1); catch (InterruptedException ie) { ScrollPane s = new ScrollPane( ScrollPane.SCROLLBARS_AS_NEEDED); fcanvas = new MyCanvas(i, s); s.add(fcanvas); s.setsize(400,400); add(s, "Center"); Scrollbar b = new Scrollbar( Scrollbar.HORIZONTAL, 5, 1, 1, 10); add(b, "South"); b.addadjustmentlistener(this);
Creating the scrollable canvas Create scroll pane, specifying it is to use scrollbars only when needed Add canvas Set size for display in applet ScrollPane s = new ScrollPane( ScrollPane.SCROLLBARS_AS_NEEDED); fcanvas = new MyCanvas(i, s); s.add(fcanvas); s.setsize(400,400); public void adjustmentvaluechanged(adjustmentevent e) { int val = e.getvalue(); fcanvas.setscale(val); class MyCanvas extends Canvas { public MyCanvas(Image i, ScrollPane s) { fimage = i; fspane = s; fex= fx = i.getwidth(this); fey = fy = i.getheight(this); setsize(fx, fy); public void paint(graphics g) { g.drawimage(fimage, 0, 0, fex, fey, this); public void setscale(int scl) { private ScrollPane fspane; private int fscale = 5; private int fx, fy; private int fex, fey; private Image fimage; public void setscale(int scl) { fscale = scl; int posx = fspane.getscrollposition().x; int posy = fspane.getscrollposition().y; int oldfex = fex; int oldfey = fey; switch(scl) { case 1: fex = fx/16 ; fey = fy/16 ; break; case 9: fex = fx*16; fey = fy*16 ; break; setsize(fex, fey); fspane.dolayout(); posx = (posx*fex) / oldfex; posy = (posy*fey) / oldfey; fspane.setscrollposition(posx, posy); repaint(); Component Button Canvas Checkbox Choice List Scrollbar TextComponent TextArea TextField TextComponents TextComponent owns text, by default is editable does return current text as String set insertion point select subset of text (by program) get current selection (as made by user) can pass on details of changes to text to a TextListener
TextComponents TextField simple one line data entry field (use illustrated in Dialog example) TextArea multiple rows, by default supports both horizontal and vertical scrolling has a replacerange() method (allowing it to be used as basis for implementing simple editor program) Dialogs Separate windows that are displayed when you need to get more data Dialog (and Filedialog) Dialog window with BorderLayout can be made modal main role is to get a set of data elements from user Filedialog for applications to pick input (or output) files Dialogs Typical approach Create dialog as part of general GUI building phase of application Keep reference to dialog object Normally, they are created invisible (not mapped to screen) When need dialog, simply setvisible(true) on dialog object Action button in dialog (or, possibly, Window-close box in dialog frame) is monitored by code in dialog; causes dialog to setvisible(false) on itself If modal dialog, main application is blocked out while dialog is visible. Purpose of dialog Generally, it is to get some extra input data Sometimes, act just as alerts pop-up, user must read, user must close Getting input: Dialog has input fields (TextField/JTextField etc) When dialog is closed (setvisible false), inputs copied into other data fields, and verified if data are ok, some boolean flag is set Data transfer Can use instance of helper class (illustrated in example) Can simply use data members of dialog class
JOptionPane JOptionPane (swing) Simple variant of dialogs Useful for error alerts in some GUI based applications Can be used to provide very simplified GUI for program that otherwise would use text inputs and output Methods in JOptionPane to put up dialog that has a textfield for input, or a dialog that offers a menu of choices for userselection This dialog example Illustrates Dialog (naturally) Data communications via an auxiliary class GridBagLayout Best (?) but most tiresome of standard layout schemes Finding parent frame (minor but necessary detail relating to use of Dialogs, particularly use with Applets) DialogExample Applet simply displays dialogs main dialog gets inputs, illustrates transfer of data back from dialog to program dialog uses a GridBagLayout label choice label label textfield label textfield button choice choice button Dialog s owner frame Dialog needs reference to owner Usually a Frame or similar object The dialog will typically position itself on the screen in front of its owner, and (if modal) will block attempts by user to click on owner. Typically, Dialogs used with GUI-based application the owner frame is then the principle Frame/Window object of the application. With Applets, can be slightly more complex; Horstmann provides example code to find appropriate Frame; Horstamann s code used here DialogExample classes DialogExample extends Applet implements ActionListener simply has button that puts up main dialog CreditCardDialog extends Dialog implements ActionListener dialog that asks for credit card details Useful a struct for moving data around
class Useful { public boolean fokd = false; public String fcard; // 1 Amex, 2 Visa, 3 public String fmonth; // Month expired public String fyear; // Year expired public String fowner; // public String fnumber; Data structure instance owned by Applet reference given to input dialog if input dialog gets an Ok action, it copies details from Choices, Textfields etc into the data structure fokd field has Ok/Cancel result from dialog Applet driver findframe - gets a pointer to window representing browser environment of applet Builds dialog initially invisible Its own display is just button with label When button pressed, causes dialog to popup Checks data returned via useful structure public class DialogExample extends java.applet.applet implements ActionListener { private Frame fframe; private Dialog fccdialog; private Useful fdataobject; public void init() { private void initcomponents() { // NetBeans generated code public void start() { private Frame findframe(component c) { public void actionperformed(actionevent evt) { // NetBeans added data members for button etc /** This method is called from within the init() method to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initcomponents() { panel1 = new java.awt.panel(); label1 = new java.awt.label(); actionbutton = new java.awt.button(); actionbutton.addactionlistener(this); setlayout(new java.awt.borderlayout()); label1.settext("please supply credit card details"); panel1.add(label1); actionbutton.setlabel("data input"); panel1.add(actionbutton); add(panel1, java.awt.borderlayout.center);
public void start() { fframe = findframe(this); fdataobject = new Useful(); fccdialog = new CreditCardDialog(fFrame, fdataobject); private Frame findframe(component c) { Frame f = null; while( (c = c.getparent())!= null) if(c instanceof Frame) f = (Frame) c; return f; Dialog created but not yet shown; data-object created, reference given to dialog which will fill in fields public void actionperformed(actionevent evt) { String s = evt.getactioncommand(); if(!s.equals("data input")) return; fccdialog.setvisible(true); if(fdataobject.fokd &&!fdataobject.fowner.equals("") &&!fdataobject.fnumber.equals("")) { System.out.println("Name " + fdataobject.fowner); System.out.println("Card " + fdataobject.fcard + " : " + fdataobject.fnumber); System.out.println("Expires " + fdataobject.fmonth + ":" + fdataobject.fyear); Show, implicitly wait for dialog to close, check response; since dialog is modal, the call setting it visible is like a procedure call that doesn t return until dialog closed action Dialog show Dialog is modal, so return from show only when dialog dismissed Check returned data, CreditCardDialog ActionListener listens to both its OK & Cancel buttons actionperformed If OK, copy inputs into data structure and set ok flag to true If Cancel, set ok flag to false Make dialog invisible public class CreditCardDialog extends Dialog implements ActionListener { private Useful ftransferbuffer; public CreditCardDialog(Frame f, Useful data) { public void actionperformed(actionevent evt) { String s = evt.getactioncommand(); if(s.equals("ok")) { ftransferbuffer.fokd = true; ftransferbuffer.fowner = fowner.gettext(); ftransferbuffer.fnumber = fnumber.gettext(); ftransferbuffer.fcard = fcardtype.getselecteditem(); ftransferbuffer.fmonth = fmonth.getselecteditem(); ftransferbuffer.fyear = fyear.getselecteditem(); else ftransferbuffer.fokd = false; setvisible(false); CreditCardDialog Construction of its GUI Lots of labels and input fields Some text inputs Some action buttons All to be arranged neatly
public CreditCardDialog(Frame f, Useful data) { super(f, "Credit Card information", true); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); setlayout(gbl); Label l; pack(); setresizable(false); ftransferbuffer = data; Code here to build elements and place in grid GridBagLayout CreditCardDialog (the one that asks for credit card details) uses GridBagLayout Detailed positioning of all the input elements etc. Invoke base class constructor to get usual dialog properties set (arguments are Frame i.e. parent, title, and modal flag; Set layout to GridBagLayout, create a (re-usable) GridBagConstraint,, complete initialization GridBagLayout Create container frame, JFrame, Create GridBagLayout formatting object and attach to container Create a GridBagConstraint object reusable fill in with data describing one of subcomponents add subcomponent to container, with GridBagConstraint object specifying where it is to go Using a GridBagLayout Create a GridBagLayout object Use this as Layout manager for Frame or Dialog or Create a GridBagConstraints object This gets re-used for each component Used to specify top-left square, width, height and other properties of region being claimed for a component Column 0 1 2 3 4 Row 0 1 2 3 label choice label label label textfield textfield button choice choice button Basically, a grid 5 columns wide, 4 rows deep Label in (0,0), choice in (0,1), Label in(0,2), choices in (0,3) & (0,4) Label in (1,0), a textfield that is 4 columns wide GridBagLayout - starting GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); setlayout(gbl);
First component A Label Text is Card To be located Row 0, column 0 1 row deep, 1 column high Label is to be in middle of its grid cell (matters if area is too large) Label is to be displayed in its natural size, it isn t to grow to fill its cell if that is larger public CreditCardDialog(Frame f, Useful data) { super(f, "Credit Card information", true); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); setlayout(gbl); Label l; l = new Label("Card"); gbc.weightx = 20; gbc.weighty = 20; Define constraints gbc.gridx = 0; gbc.gridy = 0; on position gbc.gridheight = 1; gbc.gridwidth = 1; gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.NONE; add(l, gbc); Element to be added Add element, GridBagLayout reads constraints from gbc Grid bag constraints // Location of top-left of grid // cell (area) gbc.gridx = 0; gbc.gridy = 0; // Size of cell gbc.gridheight = 1; gbc.gridwidth = 1; // Style for component in cell gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.NONE; What about the weights? Weights in constraints Supposed to give some indication to layout manager as to which components should get more of total window area if window made larger Some probably shouldn t get any larger e.g. button controls Some should get larger e.g. a Canvas or a scrollable text area Bigger weight => get more of any allocated area fcardtype = new Choice(); fcardtype.add("visa"); fcardtype.add("mastercard"); Card fcardtype.add("amex"); choice fcardtype.select("visa"); gbc.gridx = 1; gbc.weightx = 30; Each component in turn created, add(fcardtype, gbc); constraint defined, and added Label l = new Label("Expires"); gbc.gridx = 2; gbc.weightx = 20; add(l, gbc); Year fyear = new Choice(); fyear.add("2007"); fyear.select("2007"); gbc.gridx = 4; gbc.weightx = 30; add(fyear, gbc); fmonth = new Choice(); MonthfMonth.add("January"); fmonth.add("february"); fmonth.add("march"); choicefmonth.add("april"); fmonth.add("may"); fmonth.add("june"); fmonth.add("july"); fmonth.add("august"); fmonth.add("september"); fmonth.add("october"); fmonth.add("november"); fmonth.add("december"); gbc.gridx = 3; gbc.weightx = 30; add(fmonth, gbc);
Start of 2 nd row, Label for name l = new Label("Your name"); gbc.gridx = 0; gbc.gridy = 1; gbc.weightx = 20; gbc.weighty = 30; add(l, gbc); l = new Label("Card number"); gbc.gridx = 0; gbc.gridy = 2; gbc.weightx = 20; gbc.weighty = 30; gbc.gridwidth = 1; gbc.fill = GridBagConstraints.NONE; add(l, gbc); fowner = new TextField(); gbc.gridx = 1; gbc.weightx = 50; gbc.weighty = 30; gbc.gridwidth = 4; gbc.fill = GridBagConstraints.HORIZONTAL; add(fowner, gbc); Text field Multiple columns wide fnumber = new TextField(); gbc.gridx = 1; gbc.weightx = 50; gbc.weighty = 30; gbc.gridwidth = 4; gbc.fill = GridBagConstraints.HORIZONTAL; add(fnumber, gbc); Row 2 (i.e. third row), another label, another multi-column text field Button b; b = new Button("OK"); b.addactionlistener(this); gbc.gridx = 1; gbc.gridy = 3; gbc.weightx = 50; gbc.weighty = 30; gbc.gridwidth = 1; gbc.fill = GridBagConstraints.NONE; add(b, gbc); b = new Button("Cancel"); b.addactionlistener(this); gbc.gridx = 3; gbc.gridy = 3; add(b, gbc); GridBagConstraint Position and size (easy) gridx, gridy gridheight, gridwidth (define box where component to go) Where in that box? anchor GridBagConstraints: CENTER, NORTH, NORTHEAST, Finally the buttons, which get listened to GridBagConstraint Does component fill its box? Component may have natural size on platform (e.g. Button component) Box (region of grid) maybe larger Should component expand to fill? fill GridBagConstraints: NONE, HORIZONTAL, GridBagConstraint What happens if the frame is resized? Typically, some regions of display are more important and should expand (and shrink) more than others some regions maybe should stay the same size (until frame is resized so small that they just get truncated or not shown at all) weightx, weighty larger number imply greater sensitivity to size changes
GridBagLayout NetBeans GUI editor doesn t handle it too well Also, very easy for it to end up using some NetBeans GUI classes which necessitate extra library file being added to distributed application GridBagLayout coding isn t hard, just tedious GridBagLayout best for all complex forms Other dialogs FileDialog FileDialog requires reference to (parent) Frame - so application will need a simple GUI. Graphical input FileDialog fd = new FileDialog(parentFrame, title); fd.show(); String filename = fd.getfile(); awt Graphical Input You want to allow your users to sketch items in a drawable canvas pick existing items move items OK, Mouse hunt time --- MouseListener and MouseMotionListener MouseMotionListener A Component can add a MouseMotionListener When mouse moves over component (with or without button being pressed) will get motion events generated; these passed to listener mousedragged(mouseevent) called if motion with button down mousemoved(mouseevent) for motion with no button press
MouseMotionListener Use mouse motions for graphic editing dragging existing element drawing outline while adding new component Move mouse over palette; text in label field changes to give name of colour used in patch below mouse cursor. ColourPaletteTest ColourTable.java static class with table containing approx 230 colours and greyscale shades two public static arrays, Color and String (also integer count of total number colors available) a static initializer block that fills these arrays ColourPaletteTest.java ColourPaletteTest simply main() GUI extends Frame implements WindowListener builds display with a MyCanvas in center and a Panel containing two Labels at bottom; MyCanvas extends Canvas implements MouseMotionListener import java.awt.*; public class ColourTable { static public Color[] spectrum = new Color[256]; static public String[] names = new String[256]; static public int colourcount; static { Static initializer block int i = 0; spectrum[i] = new Color(255,250,250); names[i] = new String("snow"); i++; spectrum[i] = new Color(248,248,255); names[i] = new String("ghost white"); i++; spectrum[i] = new Color(245,245,245); names[i] = new String("white smoke"); i++; spectrum[i] = new Color(127,127,127); names[i] = new String("grey50"); i++; spectrum[i] = new Color(130,130,130); names[i] = new String("grey51"); i++; spectrum[i] = new Color(139, 0, 0); names[i] = new String("dark red"); i++; spectrum[i] = new Color(144,238,144); names[i] = new String("light green"); i++; colourcount = i; import java.awt.*; import java.awt.event.*; class MyCanvas extends Canvas implements MouseMotionListener { public void mousedragged(mouseevent e) { public void mousemoved(mouseevent e) { public MyCanvas(Label l) { public void paint(graphics g) { Label fname; class GUI extends Frame implements WindowListener { public void windowclosing(windowevent e) { System.exit(0); public void windowdeactivated(windowevent e) { public GUI() { public class ColourPaletteTest { public static void main(string argv[]) { GUI g = new GUI(); g.show(); class MyCanvas extends Canvas implements MouseMotionListener { public void mousemoved(mouseevent e) { int x = e.getx(); int y = e.gety(); int width = getsize().width / 16; int height = getsize().height / 16; x /= width; y /= height; int which = 16*y + x; if(which<colourtable.colourcount) fname.settext(colourtable.names[which]); else fname.settext("xxxxxxxxxxxxxxxxxxxxxxxxxxxx"); public MyCanvas(Label l) { fname = l; setsize(512,512); addmousemotionlistener(this);
MyCanvas public void paint(graphics g) { int width = getsize().width / 16; int height = getsize().height / 16; int x = 0, y = 0, col = 0; for(int i=0; i < ColourTable.colourcount; i++) { g.setcolor(colourtable.spectrum[i]); g.fillrect(x,y, width, height); g.setcolor(color.black); g.drawrect(x,y, width, height); x+=width; col++; if(col==16) { x = 0; y+= height; col = 0; class GUI extends Frame implements WindowListener { public void windowclosing(windowevent e) { System.exit(0); public void windowdeactivated(windowevent e) { public GUI() { super("color Palette"); Panel p = new Panel(); p.add(new Label("color name ")); Label l = new Label("xxxxxxxxxxxxxxxxxxxxxxxxxxxx"); p.add(l); add(p, "South"); fcanvas = new MyCanvas(l); add(fcanvas, "Center"); pack(); addwindowlistener(this); MouseListener If you aren t interested in tracking motions, you can employ a MouseListener press, release, click, enter, leave area of Component Example use a tool palette on enter, change cursor to something like cross hair on click, record which tool chosen Extras Lots More important include Tables Trees (e.g. file & directory hierarchy) Styled text documents Adjustable look and feel Decorations for other components (borders) Helper classes for editing with multiple undo operations Tables General purpose code in swing for displaying tables optionally editable options for selecting and copying data from individual table cells, table rows, or table columns Work with application defined table model this owns the data that are to be displayed provides access to info that is to be drawn in individual table cell provides table dimensions, headers, etc
public class TablePanel extends JPanel implements ActionListener { JButton selectbutton; JScrollPane sp; AddressDataTable data; JTable thetable; public TablePanel(){ data = new AddressDataTable(); thetable = new JTable(data); thetable.setcolumnselectionallowed(false); thetable.setselectionmode( ListSelectionModel.SINGLE_SELECTION); sp = new JScrollPane(theTable); public void updatedataset(vector v) { data.replacedata(v); public class AddressDataTable extends AbstractTableModel { private static final String[] columnnames = { "Suburb", "Postcode" ; private Vector data; public int getrowcount() { return data.size(); public int getcolumncount() { return 2; public void replacedata( Vector newdata) { data = newdata; firetabledatachanged(); Swing tables Seem a bit complex at first, but not really hard. You define a TableModel class Owns Collection of structs with your data; there will be a method to replace the collection with a new one when your data changes Does Report number of rows, number of columns, titles for columns Returns string for data at specified row column Fires changed events when data are changed TabbedPane Often, interface needs to display different types of data at different times data entry form error messages from processing tabular results graphic results TabbedPane model useful different tabbed panels for each facet Tabs used to switch display form
JTabbedPane JTabbedPane owns collection of components (usually JPanel subclasses) each characterized by name, optional icon, optional cntrlcharacter escape record of which component currently displayed does draws the row of tabs controls their enable/disable status handles user clicks on enabled tabs by switching panel displayed can programmatically switch between panels public class ATabbedPaneThing extends JPanel { private JTabbedPane tabbedpane; private MessagesPanel mp; private TablePanel tp; private InfoPanel ip; public ATabbedPaneThing() { tabbedpane = new JTabbedPane(); ip = new InfoPanel(this); tabbedpane.addtab("info", ip); mp = new MessagesPanel(); tabbedpane.setenabledat(2, false); setlayout(new GridLayout(1, 1)); add(tabbedpane); try { tabbedpane.setselectedcomponent(ip); catch(exception e){ Table structure Table structure can also be changed Replace the array of column names Need more sophisticated code for the elementat function Column number used to reference current column names so get name of field required Use this to select element of record structure