DECwindows Motif Guide to Application Programming


Previous Contents Index


Chapter 3
Helpful Hints for Creating a DECwindows Application

This chapter provides information and programming examples for the following topics:

3.1 Using Widgets Supplied by Digital from UIL

If you are using UIL to create instances of the print, help, color mixing, compound string text, or SVN widgets, you must add the following line to your application source file after the call to MrmInitialize:


DXmInitialize(); 

The DXmInitialize routine calls MrmRegisterClass for the widgets supplied by Digital. If you do not call DXmInitialize, you will see error messages similar to the following when you run your application:


X Toolkit Warning: Urm__WCI_LookupClassDescriptor: Couldn't find class 
descriptor for class xxxxxxx - MrmNOT_FOUND 

3.2 XmForm Widget Hints

The sections that follow describe additional XmForm widget programming hints. See the OSF/Motif Programmer's Reference for a complete description of the XmForm widget.

3.2.1 Creating a Form Dialog Box with Children

One of the common uses of the XmForm widget is to anchor rows and columns of widgets so that their alignment does not change if the size of the XmForm widget changes. The UIL example shown in Example 3-1 implements such an XmForm widget.

Example 3-1 XmForm Dialog with Children---UIL Module

   .
   .
   .
object 
    form_main : XmForm{ 
 
        arguments    
             { 
             XmNdialogTitle = compound_string("XmForm"); 
             XmNwidth = 400; 
             XmNheight = 400; 
             }; 
        (1)controls 
             { 
             XmPushButton   a_button; 
             XmPushButton   b_button; 
             XmPushButton   c_button; 
             XmPushButton   d_button; 
             XmPushButton   e_button; 
             XmPushButton   f_button; 
             XmPushButton   g_button; 
             XmPushButton   h_button; 
             XmPushButton   i_button; 
             XmPushButton   j_button; 
             }; 
    }; 
 
object 
    (2)a_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("a button"); 
              XmNtopAttachment = XmATTACH_FORM; 
              XmNtopOffset = 25; 
              XmNleftAttachment = XmATTACH_FORM; 
              XmNleftOffset = 25;    
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE; 
            }; 
    };                                  
 
object 
    (3)b_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("b button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = a_button; 
              XmNleftAttachment = XmATTACH_FORM; 
              XmNleftOffset = 25;    
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE; 
            }; 
    };                                  
 
object 
    c_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("c button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = b_button; 
              XmNleftAttachment = XmATTACH_FORM; 
              XmNleftOffset = 25;    
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
object 
    d_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("d button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = c_button; 
              XmNleftAttachment = XmATTACH_FORM; 
              XmNleftOffset = 25;    
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
object 
    e_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("e button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = d_button; 
              XmNleftAttachment = XmATTACH_FORM; 
              XmNleftOffset = 25;    
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
 
object 
    (4)f_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("f button"); 
              XmNtopAttachment = XmATTACH_FORM; 
              XmNtopOffset = 25; 
              XmNleftAttachment = XmATTACH_WIDGET; 
              XmNleftOffset = 5;    
              XmNleftWidget = a_button; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE; 
            }; 
    };                                  
 
object 
    (5)g_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("g button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = f_button; 
              XmNleftAttachment = XmATTACH_WIDGET; 
              XmNleftOffset = 5;    
              XmNleftWidget = b_button; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
object 
    h_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("h button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = g_button; 
              XmNleftAttachment = XmATTACH_WIDGET; 
              XmNleftOffset = 5;    
              XmNleftWidget = c_button; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
object 
    i_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("i button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = h_button; 
              XmNleftAttachment = XmATTACH_WIDGET; 
              XmNleftOffset = 5;    
              XmNleftWidget = d_button; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
object 
    j_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("j button"); 
              XmNtopAttachment = XmATTACH_WIDGET; 
              XmNtopOffset = 5; 
              XmNtopWidget = i_button; 
              XmNleftAttachment = XmATTACH_WIDGET; 
              XmNleftOffset = 5;    
              XmNleftWidget = e_button; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNrightAttachment = XmATTACH_NONE;   
            }; 
    };                                  
 
   .
   .
   .

  1. The XmForm widget controls 10 XmPushButton widgets.
  2. The top XmPushButton widget attaches on the top and left side to the XmForm widget, using an offset of 25.
  3. Subsequent XmPushButton widgets attach to the bottom of the XmPushButton widget directly above them and to the XmForm on the left.
    These XmPushButtons also could use XmATTACH_OPPOSITE_WIDGET to align their left sides with the left side of the a_button, as follows:


    object 
         b_button : XmPushButton { 
     
            arguments { 
                  XmNlabelString = compound_string("b button"); 
                  XmNtopAttachment = XmATTACH_WIDGET; 
                  XmNtopOffset = 5; 
                  XmNtopWidget = a_button; 
                  XmNleftAttachment = XmATTACH_OPPOSITE_WIDGET; 
                  XmNleftWidget = a_button;    
                  XmNbottomAttachment = XmATTACH_NONE; 
                  XmNrightAttachment = XmATTACH_NONE; 
                }; 
        };                                  
     
    object 
         c_button : XmPushButton { 
     
            arguments { 
                  XmNlabelString = compound_string("b button"); 
                  XmNtopAttachment = XmATTACH_WIDGET; 
                  XmNtopOffset = 5; 
                  XmNtopWidget = b_button; 
                  XmNleftAttachment = XmATTACH_OPPOSITE_WIDGET; 
                  XmNleftWidget = a_button;    
                  XmNbottomAttachment = XmATTACH_NONE; 
                  XmNrightAttachment = XmATTACH_NONE; 
                }; 
        };                                  
    

  4. Button f, like a, also attaches to the XmForm on the top, but attaches its left side to the XmPushButton on the left.
  5. Subsequent XmPushButton widgets attach to the bottom of the XmPushButton widget directly above them and to the XmPushButton on the left.
    These XmPushButtons also could use XmATTACH_OPPOSITE_WIDGET to attach their left sides to the left side of the f_button.

3.2.2 Aligning Children of Different Sizes

The UIL module shown in Example 3-1 correctly aligns the XmPushButtons and maintains this relationship regardless of the size of the XmForm. However, this alignment would be broken if the XmPushButton widgets were of different sizes. For example, a long title in button b would push button g to the right.

If your application needs to align widgets of varying sizes, you can put the XmPushButtons into XmRowColumn widgets, which expand to fit the largest child. You then align the XmRowColumn widgets within an XmForm widget.

The UIL example shown in Example 3-2 implements an XmForm widget that has children of different sizes.

Example 3-2 Aligning Children of Different Sizes

   .
   .
   .
object 
    form_main : XmForm{ 
 
        arguments    
             { 
             XmNdialogTitle = compound_string("XmForm"); 
             XmNwidth = 400; 
             XmNheight = 400; 
             }; 
 
        (1)controls 
            { 
            XmRowColumn    align_a; 
            XmRowColumn    align_b; 
            }; 
     }; 
 
                                       
object 
    align_a : XmRowColumn { 
        arguments { 
            XmNunitType = XmPIXELS; 
            (2)XmNtopAttachment = XmATTACH_FORM; 
            XmNtopOffset = 25; 
            XmNleftAttachment = XmATTACH_FORM; 
            XmNleftOffset = 25;    
            XmNbottomAttachment = XmATTACH_NONE; 
            XmNrightAttachment = XmATTACH_NONE;    
            XmNorientation = XmVERTICAL; 
            XmNborderWidth = 0; 
            };      
        controls 
             { 
             XmPushButton   a_button; 
             XmPushButton   b_button; 
             XmPushButton   c_button; 
             XmPushButton   d_button; 
             XmPushButton   e_button; 
             }; 
    }; 
 
 
object 
    a_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("a button"); 
            }; 
    };                                  
 
object 
    b_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("b button"); 
            }; 
    };                                  
 
object 
    c_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("Long Button Title"); 
            }; 
    };                                  
 
object 
    d_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("d button"); 
              }; 
    };                                  
 
object 
    e_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("Long Button Title"); 
            }; 
    };                                  
 
 
 
object 
    align_b : XmRowColumn { 
 
        arguments { 
            XmNunitType = XmPIXELS; 
            XmNtopAttachment = XmATTACH_FORM; 
            XmNtopOffset = 25; 
            (3)XmNleftAttachment = XmATTACH_WIDGET; 
            XmNleftWidget = align_a;    
            XmNleftOffset = 25; 
            XmNbottomAttachment = XmATTACH_NONE; 
            XmNrightAttachment = XmATTACH_NONE;    
            XmNorientation = XmVERTICAL; 
            XmNborderWidth = 0; 
            };      
 
        controls 
             { 
             XmPushButton   f_button; 
             XmPushButton   g_button; 
             XmPushButton   h_button; 
             XmPushButton   i_button; 
             XmPushButton   j_button; 
             }; 
    };      
 
object 
    f_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("f button"); 
            }; 
    };                                  
 
object 
    g_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("g button"); 
            }; 
    };                                  
 
object 
    h_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("h button"); 
            }; 
    };                                  
 
object 
    i_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("i button"); 
            }; 
    };                                  
 
object 
    j_button : XmPushButton { 
 
        arguments { 
              XmNlabelString = compound_string("j button"); 
            }; 
    };                                  
   .
   .
   .

  1. The XmForm widget controls two XmRowColumn widgets.
  2. XmRowColumn widget align_a is aligned to the top and left of the XmForm. It controls XmPushButtons a through e and has no visible border.
  3. XmRowColumn widget align_b is aligned to the top of the XmForm and to the right side of the align_a widget. It controls XmPushButtons f through j and has no visible border.

3.2.3 Centering Widgets at Positions Within an XmForm Widget

The XmForm widget lets you attach an edge of a widget to a position in the XmForm widget. Instead of specifying the position by its x- and y-coordinates, you specify the position as a fraction of the total dimension of the XmForm widget. This is called fractional positioning.

You specify this type of attachment by passing the attachment type constant XmNATTACH_POSITION as the value of the attachment type attribute and the numerator of the fractional position as the value of the attachment position attribute.

For example, the midpoint of the XmForm widget is one-half the distance between the two edges. To attach the left edge of a child widget to the midpoint of the XmForm widget, set the XmNleftAttachment attribute to XmNATTACH_POSITION and specify the numerator of 50 in the XmNleftPosition attribute. (The default denominator is 100.)

Note that you can also treat the XmNleftPosition argument as a percentage, where a value of 50 means 50%.

Note, however, that this aligns the left edge of the child widget with the midpoint of the XmForm widget; the child widget is not centered. To center the child widget at the midpoint, you can:

Example 3-3 and Example 3-4 show how to center child widgets by using offset values. The MrmNcreateCallback routine computes width and height offsets that center the XmPushButton widgets at their respective positions. These position and offset relationships are maintained regardless of any resizing operations performed on the XmForm widget.

Example 3-3 Centering Child Widgets at Positions in XmForm---UIL Module

   .
   .
   .
  
module form 
    version = 'v1.0' 
    names = case_sensitive 
 
procedure 
         center_form (); 
      
object 
    (1)form_main : XmForm{ 
 
        arguments    
             { 
             XmNdialogTitle = compound_string("XmForm"); 
             XmNwidth = 400; 
             XmNheight = 400; 
             }; 
        controls 
             { 
             XmPushButton   a_arrow; 
             XmPushButton   b_arrow; 
             XmPushButton   c_arrow; 
             }; 
    }; 
 
object 
    a_arrow : XmPushButton { 
 
        (2)arguments { 
              XmNlabelString = compound_string("centered"); 
              XmNtopAttachment = XmATTACH_POSITION; 
              XmNtopPosition = 50; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNleftAttachment = XmATTACH_POSITION; 
              XmNleftPosition = 25; 
              XmNrightAttachment = XmATTACH_NONE; 
            }; 
        callbacks {   
         (3)MrmNcreateCallback = procedure center_form(); 
        }; 
    };                                  
 
 
object 
    b_arrow : XmPushButton { 
 
        (4)arguments { 
              XmNlabelString = compound_string("centered"); 
              XmNtopAttachment = XmATTACH_POSITION; 
              XmNtopPosition = 50; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNleftAttachment = XmATTACH_POSITION; 
              XmNleftPosition = 50; 
              XmNrightAttachment = XmATTACH_NONE; 
            }; 
        callbacks {   
         MrmNcreateCallback = procedure center_form(); 
        }; 
    };                                  
 
object 
    c_arrow : XmPushButton { 
 
        (5)arguments { 
              XmNlabelString = compound_string("centered"); 
              XmNtopAttachment = XmATTACH_POSITION; 
              XmNtopPosition = 50; 
              XmNbottomAttachment = XmATTACH_NONE; 
              XmNleftAttachment = XmATTACH_POSITION; 
              XmNleftPosition = 75; 
              XmNrightAttachment = XmATTACH_NONE; 
            }; 
        callbacks {   
         MrmNcreateCallback = procedure center_form(); 
        };      
    };                                  
 
end module; 
   .
   .
   .

  1. Create an instance of the XmForm widget that controls an XmPushButton.
  2. This XmPushButton will be centered at 25% of the total width of the XmForm widget and 50% of its height.
  3. The center_form procedure is called when the XmPushButton widget is created. The widget is created when it is fetched.
  4. This XmPushButton will be centered at 50% of the total width of the XmForm widget and 50% of its height.
  5. This XmPushButton will be centered at 75% of the total width of the XmForm widget and 50% of its height.

Example 3-4 Centering Child Widgets at Positions in XmForm---C Module

   .
   .
   .
#include <stdio> 
#include <Mrm/MrmAppl.h>      
#include <DXm/DXmCSText.h>      
 
    
Widget toplevel, form_w; 
 
                 
static MrmHierarchy s_MrmHierarchy;   
static MrmType *dummy_class;       
static char *db_filename_vec[] = 
  {"center_form.uid"                   
  };      
 
/* Forward declarations */ 
 
static void center_form(); 
 
 
/* The names and addresses of things that Mrm has to bind.  The names do 
 * not have to be in alphabetical order.  */ 
                                              
static MrmRegisterArg reglist[] = { 
    {"center_form", (caddr_t) center_form} 
}; 
                                                        
static int reglist_num = (sizeof reglist / sizeof reglist [0]); 
 
 
int main(argc, argv) 
    unsigned int argc; 
    char **argv; 
{ 
         
    XtAppContext app_context; 
 
    MrmInitialize();   
    DXmInitialize();  
 
    toplevel = XtAppInitialize(&app_context, "example", NULL, 0, &argc, 
                             argv, NULL, NULL, 0);   
   
 
   /* Open the UID files (the output of the UIL compiler) in the hierarchy*/ 
 
    if (MrmOpenHierarchy(1, 
      db_filename_vec,     
      NULL,                
      &s_MrmHierarchy)     
      !=MrmSUCCESS) 
          printf("can't open hierarchy"); 
 
    MrmRegisterNames(reglist, reglist_num); 
 
               
    if (MrmFetchWidget(s_MrmHierarchy, "form_main", toplevel, 
      &form_w, &dummy_class) != MrmSUCCESS) 
        printf("can't fetch widget"); 
 
     XtManageChild(form_w); 
    
     XtRealizeWidget(toplevel); 
                         
     XtAppMainLoop(app_context);     
 
}                     
 
 
 
static void center_form(w, tag, reason) 
     Widget             w; 
     int               *tag;        
     unsigned long     *reason;    
 
{ 
     Arg          arglist[10];    
     int          ac; 
     int          calc_width = 0; 
     int          width_b = 0; 
     int          calc_height = 0; 
     int          height_b = 0; 
 
 
 
   /* Get the button width and height*/ 
 
     (1)ac = 0; 
     XtSetArg(arglist[ac], XmNwidth, &width_b); ac++;  
     XtSetArg(arglist[ac], XmNheight, &height_b); ac++; 
     XtGetValues(w, arglist, ac); 
              
 
   /* Calculate the button width and height */ 
  
     (2)calc_width = width_b/2; 
     calc_height = height_b/2; 
 
 
     ac = 0;                          
     (3)XtSetArg (arglist[ac], XmNleftOffset, -calc_width); ac++; 
     (4)XtSetArg (arglist[ac], XmNtopOffset, -calc_height); ac++; 
     XtSetValues (w, arglist, ac);       
                    
}                                         
   .
   .
   .

  1. Get the width and height of the XmPushButton.
  2. Calculate the offset to use. Offset the XmPushButton widget by values equal to one-half its width and one-half its height.
  3. Specify calc_width as a negative XmNleftOffset value to shift the XmPushButton to the left.
  4. Specify calc_height as a negative XmNtopOffset value to shift the XmPushButton toward the top.

3.2.4 Spacing XmPushButtons in XmForm Widgets

The Toolkit includes a routine, DXmFormSpaceButtonsEqually, that applications can call to set a variable number of push buttons in an XmForm widget so they are equally spaced and sized. DXmFormSpaceButtonsEqually determines the width of the XmForm widget and the number of XmPushButtons and then spaces and sizes the XmPushButtons accordingly.

You pass to DXmFormSpaceButtonsEqually the widget ID of the XmForm widget that contains the XmPushButtons, an array of the widget IDs of the XmPushButtons to be changed, and the number of XmPushButtons in the widget array.

You must specify the XmPushButton IDs in the order they appear in the XmForm widget; for example, OK, Apply, Reset, and Cancel. Additionally, the XmPushButtons must not have left and right attachments.

Example 3-5, the DXmFormSpaceButtonsEqually routine, is from the OpenVMS DECburger sample program. It spaces the OK, Apply, Reset, and Cancel push buttons in the XmFormDialog widget.

Example 3-5 Calling the DXmFormSpaceButtonsEqually Routine

   .
   .
   .
#define k_ok   6     /* NOTE: ok, apply, reset, cancel */ 
#define k_apply   7     /* must be sequential */ 
#define k_reset   8 
#define k_cancel  9 
 
   .
   .
   .
static void show_hide_proc(w, tag, reason) 
    Widget  w; 
    int   *tag; 
    XmAnyCallbackStruct *reason; 
{ 
    if (XtIsManaged(widget_array[k_order_box])) 
        XtUnmanageChild(widget_array[k_order_box]); 
    else { 
 start_watch(); 
        XtManageChild(widget_array[k_order_box]); 
 DXmFormSpaceButtonsEqually (widget_array[k_order_box], 
        &widget_array[k_ok], 4); 
 stop_watch(); 
    } 
} 


Previous Next Contents Index