Drawing


Drawing functions set the way to present graphical information on the screen. These range from primitive functions, such as turning a pixel on or off, to complex 2-D and 3-D drawing functions. There are some notable differences in how drawing works on X Windows and Win32 platforms.

Device Context

Applications on both platforms use a context to control how drawing functions behave. On X Windows systems, this context is known as the graphics context (GC). On Win32-based GDI systems, this context is known as the device context (DC).

The first difference is in where the operating system stores and manages drawing attributes such as the width of lines or the current font.

In X Windows, these values belong to the graphics context. When using XCreateGC() or XtGetGC() , it is necessary to provide a values mask and values structure. These values are used to store settings such as line width, foreground color, background color , and font style.

The following code is an example of the process of setting the foreground and background colors:

 GC             gcRedBlue; XGCValues      gcValues; unsigned long  gcColorRed; unsigned long  gcColorBlue; unsigned long  gcColorWhite; Widget         myWidget; int main (int args, char **argv) {    // initialize colors - widget - etc.    gcValues.foreground = gcColorRed;   gcValues.background = gcColorBlue;   gcRedBlue = XtGetGC (myWidget, GCForeground  GCBackground, &gcValues); } 

Win32-based applications use a different approach. The device context is a structure that defines a set of graphic objects and their associated attributes, as well as the graphic modes that affect output. To keep this simple, the graphic objects include a font for displaying text, a pen for line drawing, and a brush for painting and filling. To draw lines, rectangles, text, and so on, it is necessary to get or create one of these objects and select it into the desired DC.

Rather than create several specialized GC objects as X Windows does, Win32-based applications create several drawing objects and then select them into the DC as required. This methodology is similar to what an X Windows client application could do by getting a single GC and then repeatedly calling XChangeGC() .

The following code shows a Win32-based application that creates several pens and then uses them to draw lines and rectangles:

 #define onePixel    1 #define threePixels 3 #define thinLine    onePixel #define thickLine  threePixels COLORREF colorRed; COLORREF colorBlue; void drawSomthing(HDC hDC)  {   HPEN thinRedPen;   HPEN thinBluePen;   HPEN oldPen;   int  x;   int  y;   // initialize colors - etc.    //+   //  create two pens.    //  this could be done more statically somewhere so that   //  it would not be necessary to create them each time   //  this method is called.    //-   thinRedPen  = CreatePen(PS_SOLID,  thinLine, colorRed);   thinBluePen = CreatePen(PS_SOLID, thinLine, colorBlue);   x = 100;   y = 200;   //+   //  draw a line with the current pen,    //  whatever it is at this time for this DC   //-     LineTo(hDC, x,y);   //+   //  make our pen the current pen for the DC   //  and save the existing one so we can put it back   //-    oldPen = (HPEN)SelectObject(hDC, thinRedPen);   //+   //  draw a line with our pen   //-   LineTo(hDC, x,y);   //+   //  make our other pen current in the DC.    //  we are not saving the old one.   //-   SelectObject (hDC, thinBluePen);   //+   //  draw a line using our second pen   //-   LineTo(hDC, x, y);      //+   //  put back the original pen   //-   SelectObject(hDC, oldPen);   //+   //  get rid of our pen resources   //-   DeleteObject(thinRedPen);   DeleteObject(thinBluePen); } 

Getting Win32 GDI Device Context (DC)

Win32-based applications can retrieve the device context from the window handle, as shown in the following example:

 void myFunction (HWND hWnd) {   //+   //  retrieve the DC of the    //  window referenced by hWnd    //-    hDC = GetDC(hWnd);   // draw using the device context hDC   //+   // release the DC   //-    ReleaseDC(hWnd, hDC); 

Win32-based applications can also retrieve the device context in the Windows Proc by using BeginPaint() and EndPaint() , as shown in the following example:

 LRESULT CALLBACK WndProc(HWND   hWnd,                            UINT   message,                            WPARAM wParam,                            LPARAM lParam) {   HDC            hDC;   PAINTSTRUCT    ps;       switch (message) {   case WM_PAINT:     //+     //   Retrieve the device context (DC)      //   for the window referenced by hWnd      //-     hDC = BeginPaint(hWnd, &ps);          //+     //  draw with hDC or ps.hdc     //-              //+     // always follow BeginPaint() with EndPaint()     //-     EndPaint(hWnd, &ps); 

Creating Win32 GDI Device Context (DC)

It is often useful to draw in an off-screen buffer and then move that buffer into the display memory. This hides the live drawing function calls from the user and eliminates flicker in the window.

To create this off-screen context

  1. Calculate the width and height that are needed.

  2. Get the DC of the target (dialog box, button, or any other window object).

  3. Call CreateCompatibleDC .

  4. Call CreateCompatibleBitmap .

     // m_hButton is the window handle to a button.   // m_clientRect is a RECT structure.   // Step 1. Calculate the size.   GetClientRect(m_hButton, &m_clientRect);   m_width       = ((int)(m_clientRect.right  - m_clientRect.left));   m_height      = ((int)(m_clientRect.bottom - m_clientRect.top));   // Step 2. Get the DC of the target window.   hdc           = GetDC(m_hButton);   // Step 3. Create a compatible device context.   m_hdcMem      = CreateCompatibleDC(hdc);    // Step 4. Create a compatible bitmap - our X Windows drawable.   m_hbmpMem     = CreateCompatibleBitmap(hdc,m_width,m_height); 

To use and display this off-screen bitmap

  1. Select the compatible bitmap into the compatible DC.

  2. Draw on that DC.

  3. Get the target window DC.

  4. Transfer the compatible memory image to the screen.

  5. Select the old bitmap into the DC, as follows :

     // Step 1. Select the compatible bitmap into the compatible DC.   // hbmpOld is a handle to a bitmap   // m_hdcMem is the compatible device context   // m_hbmpMem is the compatible bitmap   hbmpOld = (HBITMAP)SelectObject(m_hdcMem, m_hbmpMem);   // Step 2. Draw on that DC.   // FillRect() cleans out the rectangle   FillRect(m_hdcMem, &m_clientRect, hBackgroundBrush);   // Draw a line   LineTo(m_hdcMem, x,y);   // Step 3. Get the target DC.   targetDC =  GetDC(hTargetWindow);   // Step 4. Transfer the compatible image to the screen.   // transfer everything to the screen   // hdcMem is what we drew on   //-   BitBlt(targetDC,           0,           0,           m_width,           m_height,           m_hdcMem,           0,           0,           SRCCOPY);   // Step 5. Put the old bitmap back into the compatible DC.   SelectObject(m_hdcMem, hbmpOld);    // based on program logic - Release the DC of the target window   ReleaseDC(hTargetWindow, targetDC); 

For more information about Win32-based GDI device context, search the MSDNWeb site ( http://msdn.microsoft.com/ ) for GetDC , CreateDC , CreateCompatibleDC , and DeleteDC .

Display and Color Management

X Windows and Win32-based GDI are both constrained by the physical limitations of the available display hardware. One such limitation is the number of colors a display adapter is capable of showing.

All X Windows applications use a color map. This map can be shared or private. A shared color map is used by all other applications that are not using a private map. Using a private map gives an application better color control and potentially a greater number of colors. There is one problem with private maps: When the mouse moves on or off the client by using a private map, the screen colors change.

Win32-based applications typically use color with no regard for the display device. If the application uses a color that is beyond the capabilities of the display device, the system approximates that color within the limits of the hardware. On display devices that support a color palette, applications sensitive to color quality can create and manage one or more logical palettes.

A palette is conceptually similar to an X Windows color map. Both of these methodologies are used to map some desired colors onto the physical capabilities of the display hardware. For example, if a Win32-based program needs more than 16 colors and is running on an 8-bits-per-pixel (bpp) display adapter, the program must create and use a palette.

The Win32 system palette can be thought of as similar to an X Windows shared color map. A logical palette created and realized by an application can be thought of as an X Windows private color map.

A Win32-based application that uses a logical palette exhibits some of the same behaviors as an X Windows application that uses a private color map. The application that gets priority in color selection is the one with the current focus. When the application that has the current focus calls RealizePalette() , the system palette changes and the WM_PALETTECHANGED message is sent to all top-level and overlapped windows. This message enables a window that uses a color palette but does not have the keyboard focus to realize its logical palette and update its client area. The wParam parameter identifies the owner window. Inspecting this value prevents the originating window from realizing a logical palette over and over again upon receipt of this message.

Today, most display hardware is capable of 24-bit or better color depth. For palette examples, see the many samples both on the MSDN Web site ( http://msdn.microsoft.com ) and in Microsoft Windows Platform SDK.

To create a logical color palette

  1. Allocate a LOGPALETTE structure and assign values to it.

  2. Call CreatePalette() with a pointer to the LOGPALETTE structure.

  3. Call SelectPalette() by using the pointer returned from CreatePalette() .

  4. Call RealizePalette() to make the system palette the same as the DC.

  5. Call UnrealizeObject() when finished with the palette.

To determine the capabilities of the hardware and calculate the best possible behaviors of the display, an X Windows program can use functions such as DefaultColorMap() , DefaultVisual() , DisplayCells() , DisplayPlanes() , XGetVisualInfo() and, XGetWindowAttributes() .

A Win32-based application can rely on GetDeviceCaps() for this information. The GetDeviceCaps() function retrieves device-specific information for the specified device. The following code example shows a few examples of device information that can be retrieved by using GetDeviceCaps() . For a full list of the possible values of the nIndex parameter, see the operating system Help or search the MSDN Web site ( http://msdn.microsoft.com/ ).

 int GetDeviceCaps(HDC hdc,     // handle to DC   int nIndex   // index of capability); void myFunction(HWND hThisWindow) {   HDC hDC;   hDC = GetDC(hThisWindow);   widthOfScreenInPixels    = GetDeviceCaps(hDC, HORZRES);   numberOfColorPlanes      = GetDeviceCaps(hDC, PLANES);   numberOfColors           = GetDeviceCaps(hDC, NUMCOLORS);   numberOfFonts            = GetDeviceCaps(hDC, NUMFONTS); } 

Drawing 2-D Lines and Shapes

The device context of a drawing surface contains attributes that directly affect how lines, curves, and rectangles are drawn. These attributes include the current brush and pen and current position.

The default current position for any given DC is (0,0) in logical (world) 2-D space. The value of the current position can be changed by calling MoveToEx() , as shown in the following code example. The MoveToEx() function updates the current position to the specified point and optionally returns the previous position. This function affects all drawing functions.

 BOOL MoveToEx(HDC hdc,          // handle to device context   int X,            // x-coordinate of new current position   int Y,            // y-coordinate of new current position   LPPOINT lpPoint   // old current position); 

The POINT structure defines the x and y coordinates of a point, as shown in the following code example:

 typedef struct tagPOINT {    LONG x;    LONG y;  } POINT, *PPOINT; 

Drawing Lines

Two sets of line and curve drawing functions are provided in the Win32 GDI API. These two sets of functions are identified by the letters To at the end of the function name . Functions ending with To use and set the current position. Those that do not end with To leave the current position as it was.

The LineTo function draws a line from the current position up to, but not including, the specified point, as shown in the following code example:

 BOOL LineTo(HDC hdc,    // device context handle   int nXEnd,  // x-coordinate of ending point   int nYEnd   // y-coordinate of ending point); 

The PolylineTo function draws one or more straight lines that use and update the current position. A line is drawn from the current position to the first point specified by the lppt parameter by using the current pen. For each additional line, the function draws from the ending point of the previous line to the next point specified by lppt, as shown in the following code example:

 BOOL PolylineTo(HDC          hdc,   // handle to device context   CONST POINT *lppt,  // array of points   DWORD        cCount // number of points in array); 

The Polyline function draws a series of line segments by connecting the points in the specified array, as shown in the following code example. The lines are drawn from the first point through subsequent points by using the current pen. Unlike the LineTo() or PolylineTo() functions, the Polyline() function neither uses nor updates the current position.

 BOOL Polyline(HDChdc,    // handle to device context   CONST POINT *lppt,   // array of endpoints   intcPoints // number of points in array); 

The following X Windows example shows the use of XDrawLine() :

 int main (int argc, char **argv) {    XtToolkitInitialize ();      myApplication = XtCreateApplicationContext ();      myDisplay     = XtOpenDisplay(myApplication,                                   NULL,                                   NULL,                                   "XBlaat",                                   NULL,                                   0,                                   &argc,                                   argv);   myWindow = RootWindowOfScreen(DefaultScreenOfDisplay (mydisplay));   //+   // now we need a surface to draw on   //-   myMap = XCreatePixmap (myDisplay,myWindow,64,64, 1);   values.foreground =      BlackPixel (myDisplay, DefaultScreen (myDisplay));     myGC = XCreateGC (myDisplay, mySurface, GCForeground, &values);   //+   //  draw two diagonal lines across the 64x64 surface   //     XDrawLine(myDisplay,mySurface,myGC,0,0,63,63);    XDrawLine(myDisplay,mySurface,myGC,0,63,63,0);    } 

The following Win32 example shows the use of MoveToEx() and LineTo() :

 void lineExampleIn64X64Window(HDC hDC, HPEN myBlackPen) {   HPEN oldPen; //+   //  use a black pen   //-   oldPen = (HPEN)SelectObject(hDC, myBlackPen);   //+   //  set the current position.   //  this would not be necessary if it was    //  known that the current position    //  was already at (0,0).   //-   MoveToEx(hDC, 0,0, NULL);   //+   //  now the current position is at (63,63)   //-   LineTo(hDC, 63,63);   //+   //  set the current position to the lower left corner   //-   MoveToEx(hDC, 0,63, NULL);   //+   //  draw the second diagonal   //  and make the current position (63,0)   //   //- LineTo(hDC, 63, 0);   //+   // put back the old pen   //-    SelectObject(hDC, oldPen); } 

Drawing Rectangles

In Win32, Rectangle shape is a filled shape. Filled shapes are geometric forms that the current pen can outline and the current brush can fill.

There are five filled shapes:

  • Ellipse

  • Chord

  • Pie

  • Polygon

  • Rectangle

In X Windows, the XRectangle shape is quite different from the Win32 equivalent. When porting between the two, it is necessary to understand the conceptual difference. The X Windows version uses an upper-left -corner point and the width and height. The Win32 version uses the upper left and lower right points. This difference is also true for the XDrawRectangle() and Win32 Rectangle() functions.

The X Windows structure is as follows:

 typedef struct {   short x,y;   unsigned short width,height; } XRectangle; 

Its Win32 equivalent is as follows:

 typedef struct _RECT {    LONG left;    LONG top;    LONG right;    LONG bottom;  } RECT, *PRECT; 

The Rectangle() function draws a rectangle. The rectangle is outlined by using the current pen and filled by using the current brush. Because it does not fill the rectangle, this function is quite different from the XDrawRectangle() function.

 BOOL Rectangle(HDC hdc,         // handle to DC   int nLeftRect,   // x-coord of upper-left corner of rectangle   int nTopRect,    // y-coord of upper-left corner of rectangle   int nRightRect,  // x-coord of lower-right corner of rectangle   int nBottomRect  // y-coord of lower-right corner of rectangle); 

Rectangle functions that fill the rectangle are:

  • X Windows: XFillRectangle()

  • Win32: Rectangle()

  • Win32: FillRect()

Rectangle functions that draw the outline only are:

  • X Windows: XDrawRectangle()

  • Win32: FrameRect()

Note  

The Win32 functions Rectangle() and FillRect() differ in the parameters they take. For more information, see Visual Studio Help or the MSDN Web site, http://msdn.microsoft.com/ .

The following X Windows example demonstrates rectangle functions:

 void drawSomeRectangles() {   //+   // fill the rectangle and then draw a black border around it   //-   XFillRectangle (myDisplay, mySurface, myWhiteGC, 0, 0, 31, 31);   XDrawRectangle (myDisplay, mySurface, myBlackGC, 0, 0, 31, 31);   //+   //  draw an empty rectangle ten pixels square   //-    XDrawRectangle(myDislay, mySurface, myBlackGC, 0,0, 10,10); } 

The following Win32 example demonstrates rectangle functions:

 void drawSomeRectangles() {   RECT myRectangle;       //+   // fill the rectangle and then draw a black border around it   // assume that the current pen in this DC is black and the    // current brush is not    //-   Rectangle(hDC, 0,0,31,31);     //+   //  draw an empty rectangle ten pixels square   //  The FrameRect() function draws a border around the specified               //  rectangle by using the specified brush rather than the current   //  pen.   //     //  The width and height of the border are always one logical unit.   //-    myRectangle.Top     = 0;   myRectangle.Left    = 0;   myRectangle.Bottom  = 10;   myRectangle.Right   = 10;     FrameRect(hDC, &myRectangle, myBlackBrush); } 



UNIX Application Migration Guide
Unix Application Migration Guide (Patterns & Practices)
ISBN: 0735618380
EAN: 2147483647
Year: 2003
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net