2D Graphics and User Interfaces

Why graphics first?

Everything on the screen is graphics.  Everything.

Without understanding how things get drawn on the screen, one can not understand how interfaces are created, and one can not create new kinds of interfaces at all.

  

  

Graphics description models

Stroke model describes images with strokes of specified color and thickness.  There are also several other parameters, such as how the line segments are connected, and whether the line is drawn solid, or with dashes.  In addition, strokes can be antialiased.

Line from (4,5) to (9,7) in red with a thickness of 5
Circle centered at (19,8) in blue with a radius of 8 and a thickness of 3
...

 

 
Miter Join


Round Join


Bevel Join

an example implementation: Quartz 2D

Pixel model describes images as a discrete number of pixels. Each pixel is specified by a color from one of several possible color models.

         
Antialiasing a line

Region model describes images with filled areas such as arcs, text, splines, and other shapes - often other stroke objects.  The area may be filled with a color, or a more complex fill such as a gradient or texture.

Polygon filling (0, 0)-(10, 5)-(5, 10) with yellow
...

Solid fill:    Gradient fill:

In practice, graphics are described with a combination of stroke, region, and pixel descriptions.

The drawing abstraction

Every computer graphics system (i.e., operating system) offers some notion of a canvas to draw onto. 

Usually, the canvases are separated into windows that are distinct from each other, which provide a relative coordinate system and isolation.  This abstraction allows the same binary-level application to render onto different kinds of surfaces such as screens, off-screen buffers (i.e., clipboards), and printers, plotters, and direct neural implants...

Most current systems offer a a resolution-independent (or device-independent) API.  This is crucial.  If all rendering was done in pixels, a 100 pixel rectangle would be about an inch big on most displays, but would be less than 1/10th of an inch big on some printers.

Java offers the Graphics/Graphics2D classes that present this abstraction

Graphics objects

Graphics object (device context) provides an interface between the application program and the display device. An uniform set of graphics primitives is provided for very different devices: display screen, printer, image file, ...


In Java AWT (abstract windowing toolkit) the Graphics object is an instance of the class java.awt.Graphics. It is normally obtained as a parameter to the window update function.

public void paint(Graphics g) {
  g.setColor(Color.red);
  g.fillRect(10, 10, 100, 200);

  Graphics2D g2 = (Graphics2D)g;   // g is actually an instance of a Graphics2D
  g2.draw(...);
}

Graphics holds state that prescribes how future Graphics method calls will actually behave.

There is a difference in Java & C# between what state Graphics holds, and what values are passed in as parameters to the render methods.

Example: Java Graphics has Color state, and uses a Color for stroke and fill (of Graphics), and uses a Paint for fill (of Graphics2D)

g.setColor(Color.red);
g.drawLine(0, 5, 10, 15);
g.drawLine(50, 50, 30, 20);

C# Graphics does not have Color state, but instead requires Pen and Brush objects passed as parameters

Pen redPen = new Pen(Color.Red);
g.DrawLine(redPen, 0, 5, 10, 15);
g.DrawLine(redPen, 50, 50, 30, 20);

What are the tradeoffs between these two approaches?

How to do it

The Paint Method Regardless of how a paint request is triggered, the AWT uses a "callback" mechanism for painting, and this mechanism is the same for both heavyweight and lightweight components. This means that a program should place the component's rendering code inside a particular overridden method, and the toolkit will invoke this method when it's time to paint. The method to be overridden is in java.awt.Component:

public void paint(Graphics g)

When AWT invokes this method, the Graphics object parameter is pre-configured with the appropriate state for drawing on this particular component:
The Graphics object's color is set to the component's foreground property. The Graphics object's font is set to the component's font property. The Graphics object's translation is set such that the coordinate (0,0) represents the upper left corner of the component. The Graphics object's clip rectangle is set to the area of the component that is in need of repainting. Programs must use this Graphics object (or one derived from it) to render output. They are free to change the state of the Graphics object as necessary.

Painting in AWT and Swing

Coordinate systems

Device coordinates - Coordinates of the physical device:

  • Usually has origin (0, 0) at upper left
  • X increases to the right
  • Y increases down
  • Integral coordinates always has X in  [0, width] and Y in [0, height]
  • Coordinates correspond to pixels
  • Need to know pixel density (DPI) to create a specific-sized object

Window coordinates - Coordinates within an operating system window

  • Similar to device coordinates
  • If there is a frame around the window ("window dressing"), that is outside the dimensions of the window

Physical coordinates ("device-independent coords") - correspond to physical measurements

  • Defined in universal measurements - inches, millimeters, points (1/72 of an inch)
  • Necessary to make graphics the same size independent of device

Model ("local") coordinates - correspond to the object you are defining

  • You may want to define an application-specific coordinate system
  • I.e., Origin at the center of screen with one "unit" per inch

Drawing shapes

Java Graphics has basic shape support: lines, ellipses, polygons, etc.

Java Graphics2D also has generic Shape class with g2.draw() and g2.fill() methods.  See java.awt.geom.

Lots of Shape subclasses.

Rendering - Damage/Redraw

Override the appropriate paint method of your canvas.

Render when you are asked to.

Request to be rendered with JComponent.repaint()  Remember that these only request repaints to happen in the future, they do not happen immediately.

Or, just repaint a portion of the canvas - repaint(x, y, w, h)   

Be careful to not to request a repaint within a paint method.  Why?

Double Buffering

Without care, animated displays will flicker

Due to user seeing sequence of render actions - background cleared, then items drawn back to front

Instead, create offscreen buffer (or "back buffer").  Render onto that, and then copy entire back buffer to screen at once.  This eliminates flicker, and can be faster for some display hardware - but uses more memory.

See here for examples.

Text

A special kind of graphics for both performance and human reasons.

Fonts can be bitmaps or curves (or bitmaps generated from curves)

Java

g.setFont(font);
g.setColor(color);
g.drawString(string, x, y);

How big is a point?

Fonts get measured with Ascent, Descent, Height, Leading, Width, Kerning

Higher quality text can be drawn with antialiasing or more recently, sub-pixel antialiasing (e.g., Microsoft Cleartype)