The graphics model used here is different. It is based on widgets which are transparent areas of the screen and which are painted back-to-front order as required. All painting is done to an off-screen buffer.
public void paint(Graphics g) { ... } public void paint(Graphics g, int x, int y, int width, int height) { paint(g); }The first version of the paint methods is used in most cases. If you create your own widget, or if you want to define the look of an existing widget you need to override this method.
The second version of the paint method is always called first. The additional arguments defined the area of the widget (in local coordinates) which needs painting. Complex widgets should override this method and only draw the components that lie within this area to avoid doing unnecessary work. Simple widgets can simply override the first version of the paint method which is called if the second version is not overridden.
When the paint method is called the graphics context which is passed in as an argument is initialized accordingly. The translation is according to the widget's coordinate system, the clipping rect is set to the area that needs painting, the color is set the widget's foreground color, and the font is set to the widget's current font.
Here is an example of a typical paint method which draws raised oval button with a label in the center:
import java.awt.*; import marimba.gui.*; public class RoundButtonWidget extends Widget { String label; boolean fill; boolean down; ... public void paint(Graphics g) { FontMetrics fm = g.getFontMetrics(); // Draw the button g.setColor(background); if (fill) { Bevel.fillOval(g, 0, 0, width, height, !down, 2); } else { Bevel.drawOval(g, 0, 0, width, height, !down, 2); } // Draw the label if (label != null) { g.setColor(foreground); int lx = (width - fm.stringWidth(label))/2; int ly = (height - fm.getHeight())/2 + fm.getAscent(); if (down) { g.drawString(label, lx+1, ly+1); } else { g.drawString(label, lx, ly); } } } ... }
To avoid unnecessary use of memory only one off-screen buffer is used to paint all widgets in the system. Instead of allocating a different off-screen buffer for each window, the same off-screen buffer is used to draw into all window. This uses much less memory and does not affect the graphics model.
If a widget changes, it can't immediately draw to the screen. Widgets need to be drawn in back-to-front order to maintain the correct stacking order. The underlying system takes care of painting the necessary widgets in the correct order.
The repaint method can be called on any widget. It comes in several flavors:
// repaint the entire widget public void repaint(); // repaint a portion of a widget public void repaint(int x, int y, int width, int height); // repaint a portion of a widget with a given delay public void repaint(long delay, int x, int y, int width, int height);Each of these version of repaint will eventually result in a call to paint unless the widget is not currently visible.
The last version of repaint allows you to specify a delay in milli-seconds. This delay indicates to the system how long the subsequent paint event can be delayed. This version of repaint should be used when repaint is called very frequently (line in an animation).
After calling repaint the system will automatically call the widget's paint method. Not every call to repaint will result in a corresponding call to paint. It the system is very busy it is allowed to collapse multiple calls to repaint into a single call to paint.
Here is an example of how repaint is used in the handleEvent method of the OvalButtonWidget class:
import java.awt.*; import marimba.gui.*; public class RoundButtonWidget extends Widget ... public boolean handleEvent(Event evt) { switch (evt.id) { case Event.MOUSE_DOWN: down = true; repaint(); return true; case Event.MOUSE_UP: down = false; repaint(); return true; } return super.handleEvent(evt); } }The paint method is called automatically after calling repaint. All widgets that occupy the same area of the screen as this button widget will be redrawn in the correct order. This way the button will redraw correctly even if there are other widgets above and below it.
The source code for this example is included in the release. It is located in the demo/programming directory.
AWT component support is provided for backward compatibility with existing widgets and applets. Mixing AWT components and widgets on a regular basis is not recommended.