Graphics

PGUI: Graphics

Device independent graphics is at the core of GUI programming. The central concepts are described below.

Image models

Stroke model describes images with strokes of specified color and thickness.

Line((4,5)(9,7) thick 1)
Circle((19,8) radius 3 thick 3)
...

Pixel model describes images as discrete number of pixels. It is used for drawing images and sometimes text (glyphs).

Region model describes images with filled region. The regions are specified with stroke objects. The model is used for drawing complex area like characters (glyphs).

Coordinate systems

In normal cartesian coordinates the x-coordinate grows to the right and the y-coordinate upwards.

The y-coordinate of the device coordinates usually grows downwards. The origin of the device coordinates is at the top-left corner of the display area.

The window coordinates are local to the window but otherwise similar to the device coordinates.

Logical coordinates define a mapping between the coordinates used in the application and the device coordinates. The direction and units of the logical coordinates can be anything.

Example

Exactly 1 centimeter square can be drawn in Win32 with the code

SetMapMode(hdc, MM_LOMETRIC);

Rectangle(hdc, 100, -100, 200, -200);

This results to the following drawing. Notice that the direction of the logical coordinates in MM_LOMETRIC is the same as in the cartesian coordinates. The origin is still at the top-left corner, hence the negative values.

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);
}

The real type of the graphics object in Java2 is java.awt.Graphics2D. The parameter g could be type-casted to this more complex type.

.NET also has a Graphics class in the System.Drawing namespace. The use of the class and it's instances is very similar to the use of java.awt.Graphics.

In Win32 API programming the graphics interface is implemented in a data structure called device context (data type DC). A handle HDC is used to refer to the data structure. DC is usually obtained in handling the WM_PAINT -message.

HDC hdc;
PAINTSTRUCT ps;

switch (message) {
...    
case WM_PAINT: {
  hdc = BeginPaint (hwnd, &ps);
  Rectangle(hdc, 10, 10, 110, 210
  EndPaint (hwnd, &ps);
  return 0;
}
...

MFC provides special DC -classes derived from a base class CDC. The most common of these is the one used in window update operations (CPaintDC).

void CChildView::OnPaint() 
{
  CPaintDC dc(this);
  // piirtofunktioiden kutsu, esim
  dc.Rectangle(10, 10, 110, 210);
}

Clipping with regions

The windows (and also applications) share the same display device (screen). There must be a way to prevent the application from drawing on the other windows.

Clipping region or clip region is a data structure that holds the information about the allowed region for drawing. In the simplest case the clip region is a rectangle encompassing the client (or content) area of the window.

The content area as a clip region inside the blue border.

The clip region gets more complex if the window is obscured by other windows. In this case the region can be described by a list of rectangles.

A more complex clip region inside the blue border.

The clip region is maintained by the windowing system on behalf of the application. The application can draw in any location of the window. Drawing is visible only inside the clip region.

Updating the window

The content area of the window needs to be redrawn frequently in response of different events. This process is called updating (or redrawing). For instance, if the lowest window in the picture above is activated, a postion of the window is revealed from behind the other windows.

The revealed region region inside the red border.

The graphical environment is responsible for updating the frame of the window. The application updates the intersection of the revealed region and the content area. This region is called the update region.

The revealed region region inside the red border.
The content area inside the blue border.
The update region drawn in magenta.

The update region is automatically set as the clip region in the update message processing. Thus, the application programmer can draw in any location of the window. Drawing is visible only in the update region.

In Windows, the update is done while processing the WM_PAINT event message. In MFC this is done with member function OnPaint. In windows API programming, the graphics device context comes from the function BeginPaint. In MFC, one just has to create a CPaintDC object.

A Java UI component implements the method paint for updating the content area of the component. The graphics object is a parameter to the method.

It is possible to cause the update to happen. In Windows you can do this by calling function InvalidateRect (API) or CWnd::InvalidateRect (MFC). In Java, the corresponding method is repaint (more accurately, Component.repaint).

Colors

RGB model represents colors by mixing red green and blue colors. All colors that can be sensed by the retina can be expressed by 6 bits per primary color (18 bits total). However, the complete ocular system can sense more levels of intensity. 256 levels of intensity for each primary color are more than enough. Thus 24 bits per pixel is enough for expressing the colors.

The Java class for representing colors is java.awt.Color.

Color c = new Color(255, 0, 0);
graphics.setColor(c);
// drawing

The includes a set of predefined RGB colors as static members. For instance, to get a red color, we can write Color.Red.

.NET has a Color class in the namespace System.Drawing. It also includes pre-defined colors (a very large collection).

In Windows API, special objects are used both for drawing lines and filling shapes. Color data type is COLORREF. Colors are created with RGB-macro.

Pens, strokes and brushes

The graphics interfaces usually provide means for defining line styles and fill colors wiht special objects.. Pens, strokes and brushes are such objects.

Windows API uses a PEN structure for defining different aspects of the lines drawn on the DC. The application code refers to the PEN structure with HPEN handle. MFC includes a class called CPen for describing pens.

Java 2D graphics uses an interface called java.awt.Stroke for defining line styles. The library includes only one concrete subclass called java.awt.BasicStroke.

The following table shows an example of the use of pens and strokes for setting line styles. The table includes three pictures and the code needed to produce the pictures with Java and MFC. Java examples are taken from inside paint(Graphics g) -function and share the following code:

int xp[] = {50, 100, 80};
int yp[] = {50, 50, 100};
Graphics2D g2d = (Graphics2D) g;
BasicStroke thin = new BasicStroke(1);
/* Insert code into here */
g2d.drawPolyline(xp, yp, 3);
g2d.setStroke(thin);
g2d.setColor(Color.black);
g2d.drawPolyline(xp, yp, 3);

The MFC examples are taken from OnPaint() -message handler and need the following code:

CPaintDC dc(this);

CPoint pts[] = {
CPoint(50, 50),
CPoint(100, 50), CPoint(80, 100)
}; CPen thin(PS_SOLID, 1, RGB(0, 0, 0)); /* Insert code into here */ dc.Polyline(pts, 3); dc.SelectObject(thin); dc.Polyline(pts, 3);
Picture Java (inserted code) MFC (inserted code)
BasicStroke s = 
  new BasicStroke(20, 
    BasicStroke.CAP_ROUND, 
    BasicStroke.JOIN_ROUND
  );
g2d.setStroke(s);
g2d.setColor(new Color(255, 51, 51));
CPen p(
  PS_SOLID | PS_JOIN_ROUND, 
  20, RGB(255, 51, 51)
);
dc.SelectObject(p);

BasicStroke s = 
  new BasicStroke(20, 
    BasicStroke.CAP_SQUARE, 
    BasicStroke.JOIN_BEVEL
  );
g2d.setStroke(s);
g2d.setColor(new Color(51, 255, 51));
LOGBRUSH lb = 
  {BS_SOLID, RGB(51, 255, 51), 0};
CPen p(
  PS_GEOMETRIC |
    PS_SOLID | 
    PS_ENDCAP_SQUARE |
    PS_JOIN_BEVEL, 
  20, &lb, 0, NULL
);
dc.SelectObject(p);
BasicStroke s = 
  new BasicStroke(20, 
    BasicStroke.CAP_BUTT, 
    BasicStroke.JOIN_MITER
  );
g2d.setStroke(s);
g2d.setColor(new Color(51, 51, 255));
LOGBRUSH lb = 
  {BS_SOLID, RGB(51, 51, 255), 0};
CPen p(
  PS_GEOMETRIC |
    PS_SOLID | 
    PS_ENDCAP_FLAT |
    PS_JOIN_MITER, 
  20, &lb, 0, NULL
);
dc.SelectObject(p);

Shapes are filled by using a simple color definition (Java) or a more complex brush object (Win). Brush objects define the color and the pattern of the filled area. Class CBrush describes a brush in MFC. Win API uses a HBRUSH handle. The followin image

can be drawn with MFC code:

CBrush solid;
solid.CreateSolidBrush(RGB(51, 51, 255));
dc.SelectObject(solid);
dc.Rectangle(10, 10, 70, 70);
CBrush hatched; hatched.CreateHatchBrush(HS_DIAGCROSS, RGB(51, 51, 255)); dc.SelectObject(hatched); dc.Rectangle(100, 10, 160, 70);

Drawing simple shapes

The general drawing functions are, in object-oriented programming, defined as member functions of the graphics object class.

The list of the different drawing functions in Java see the documentation on java.awt.Graphics and java.awt.Graphics2D

For the list of the MFC drawing functions, see the documentation of CDC in the MSDN Library. The windows API functions are listed in the Painting and drawing reference.

See the simple graphics example for demonstration of some of the graphics functions available.

Drawing bitmap images

Java has a good support for handling images with the common formats GIF and JPEG. The class java.awt.Image can be used for representing bitmap images. The class java.awt.Toolkit is useful in loading bitmap images into memory. Graphics objects has basic methods for drawing images scaled into any size.

Windows API includes good support for using bitmap images with BMP-format. The easiest way to utilize images in an application is to spesify them as resources into the application. The following line in any resource script file (.rc) makes a bitmap image (with name grub.bmp) available as a resource:

IDB_GRUB BITMAP DISCARDABLE "grub.bmp"

with an integer id (IDB_GRUB) defined in a header file. The bitmap can be loaded with API function LoadBitmap. In roder to draw an image we need to create a device context for the image and use any -Blt -function to accomplish the drawing.

MFC has a special class called CBitmap for managing bitmap images. The class makes it easy to load bitmaps. The drawing happens similarly to the plain API programming.

See example program Image for further information.

See also:
Simple graphics example
Image example
Hello, World -examples

Package java.awt
Windows GDI

Namespace System.Drawing