www.gibmonks.com




  Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 46.  Writing a Tk Widget in C


The Widget Instance Command

For each instance of a widget, a new command is created that operates on that widget. This is called the widget instance command. Its name is the same as the Tk pathname of the widget. In the clock example, all that is done on instances is to query and change their attributes. Most of the work is done by Tk_ConfigureWidget and ClockConfigure, which are shown in the next section. The ClockInstanceCmd command procedure is shown in the next example:

Example 46-5 The ClockInstanceCmd command procedure.
static int
ClockInstanceCmd(clientData, interp, argc, argv)
   ClientData clientData;/* A pointer to a Clock struct */
   Tcl_Interp *interp;  /* The interpreter */
   int argc;            /* The number of arguments */
   char *argv[];        /* The command line arguments */
{
   Clock *clockPtr = (Clock *)clientData;
   int result = TCL_OK;
   char c;
   int len;
   if (argc < 2) {
      Tcl_AppendResult(interp, "wrong # args: should be \"",
         argv[0], " option ?arg arg ...?\"", (char *) NULL);
      return TCL_ERROR;
   }
   c = argv[1][0];
   len = strlen(argv[1]);
   if ((c == 'c') && (strncmp(argv[1], "cget", len) == 0)
          && (len >= 2)) {
      if (argc != 3) {
         Tcl_AppendResult(interp,
             "wrong # args: should be \"",
            argv[0], " cget option\"",
            (char *) NULL);
         return TCL_ERROR;
      }
      result = Tk_ConfigureValue(interp, clockPtr->tkwin,
          configSpecs, (char *) clockPtr, argv[2], 0);
   } else if ((c == 'c') && (strncmp(argv[1], "configure", len)
             == 0) && (len >= 2)) {
      if (argc == 2) {
         /*
          * Return all configuration information.
          */
         result = Tk_ConfigureInfo(interp, clockPtr->tkwin,
            configSpecs, (char *) clockPtr,
            (char *) NULL,0);
      } else if (argc == 3) {
         /*
          * Return info about one attribute, like cget.
          */
         result = Tk_ConfigureInfo(interp, clockPtr->tkwin,
            configSpecs, (char *) clockPtr, argv[2], 0);
      } else {
         /*
          * Change one or more attributes.
          */
          result = ClockConfigure(interp, clockPtr, argc-2,
             argv+2,TK_CONFIG_ARGV_ONLY);
      }
   } else {
      Tcl_AppendResult(interp, "bad option \"", argv[1],
         "\": must be cget, configure, position, or size",
         (char *) NULL);
      return TCL_ERROR;
   }
   return result;
}

Example 46-6 shows the ClockInstanceObjCmd procedure. It uses the Tk_GetIndexFromObj routine to map the first argument to an index, which is then used in a switch statement. It uses the Tk_GetOptionValue and Tk_GetOptionInfo procedures to parse the widget configuration options.

Example 46-6 The ClockInstanceObjCmd command procedure.
static int
ClockInstanceObjCmd(clientData, interp, objc, objv)
   ClientData clientData;/* A pointer to a Clock struct */
   Tcl_Interp *interp; /* The interpreter */
   int objc;           /* The number of arguments */
   Tcl_Obj *objv[];    /* The command line arguments */
{
   Clock *clockPtr = (Clock *)clientData;
   char *commands[] = {"cget", "configure", NULL};
   enum command {CLOCK_CGET, CLOCK_CONFIGURE};
   int result;
   Tcl_Obj *objPtr;
   int index;

   if (objc < 2) {
      Tcl_WrongNumArgs(interp, 1, objv,
         "option ?arg arg ...?");
      return TCL_ERROR;
   }
   result = Tcl_GetIndexFromObj(interp, objv[1], commands,
         "option", 0, &index);
   if (result != TCL_OK) {
      return result;
   }
   switch (index) {
      case CLOCK_CGET: {
         if (objc != 3) {
            Tcl_WrongNumArgs(interp, 1, objv,
               "cget option");
            return TCL_ERROR;
         }
         objPtr = Tk_GetOptionValue(interp,
                (char *)clockPtr,
                clockPtr->optionTable,
                (objc == 3) ? objv[2] : NULL,
                clockPtr->tkwin);
         if (objPtr == NULL) {
            return TCL_ERROR;
         } else {
           Tcl_SetObjResult(interp, objPtr);
         }
         break;
      }
      case CLOCK_CONFIGURE: {
         if (objc <= 3) {
            /*
             * Return one item if the option is given,
             * or return all configuration information.
             */
            objPtr = Tk_GetOptionInfo(interp,
                   (char *) clockPtr,
                   clockPtr->optionTable,
                   (objc == 3) ? objv[2] : NULL,
                   clockPtr->tkwin);
            if (objPtr == NULL) {
               return TCL_ERROR;
            } else {
              Tcl_SetObjResult(interp, objPtr);
            }
         } else {
            /*
             * Change one or more attributes.
             */
            result = ClockObjConfigure(interp, clockPtr,
               objc-2, objv+2);
         }
      }
   }
   return TCL_OK;
}

      Previous section   Next section
    Top