Version 1 of mghello

Updated 2004-08-21 13:00:22

(update from mghello --> mgsimple) (from SUN FTP archive) (Excuse the formatting - no time to edit WIKI - copy entire contents into plaintext if you want to try it - and folow directions)

There are 3 files here. They are "simple.c", "simple.tk", and "makefile".

This example creates a new Tk_Main and Tcl_AppInit. This example strips lots of extra code out of Tk_Main, and allows a cleaner startup of your own C + Tk application. This example will compile for Tk4.1/Tcl7.5 and Tk8.0+/Tcl8.0+.

This example illustrates a method of creating a GUI with Tk that will work with your C application. It illustrates the sharing of variables between C and Tk, and a method of registering your own C commands to call from Tk.

To try this example: Create a new directory for these files. Cut each section and save with the correct name. Edit and execute the makefile. It will work without too much trouble. The file simple.tk will fail to execute if the end of lines aren't UNIX end of lines. Double check them if you have problems.

Execute in the background by simply typing: simple &

-----------------cut and name file "simple.c"---------------------------- /*

 *  Copyright :)
 *  Michael K. Ganley
 *  
 *  20 January 1997
 *  Simple C + Tk example
 */

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <tk.h>

typedef int (Tcl_myAppInitProc) _ANSI_ARGS_((int argc, char **argv,

    Tcl_Interp *interp ));

void Tk_myMain _ANSI_ARGS_((int argc, char **argv,

    Tcl_myAppInitProc *appInitProc));

int Tcl_myAppInit _ANSI_ARGS_((int argc, char **argv,

    Tcl_Interp *interp ));

int getSumExampleCmd _ANSI_ARGS_((ClientData, Tcl_Interp *,

    int, char **));

static Tcl_Interp *interp; static int alive = 1;

/*

 *
 * main --
 *
 */

main(int argc, char *argv) {

    Tk_myMain( argc, argv, Tcl_myAppInit);
    return(0);

}

/*

 *
 * Tk_myMain ----
 *
 */

void Tk_myMain( int argc, char **argv, Tcl_myAppInitProc

   *myappInitProc )

{

Tcl_FindExecutable( argv0 ); interp = Tcl_CreateInterp();

if( ( *myappInitProc )( argc, argv, interp ) != TCL_OK )

    {
    fprintf( stderr, "\nUnexpected application error!" );
    }

Tcl_Exit(0);

}

/*

 *
 * Tcl_myAppInit --
 * 
 */

int Tcl_myAppInit( int argc, char *argv, Tcl_Interp *interp ) {

    int         retcode;
    Tk_Window   mainWindow;
    int         share2 = 0;

    if( Tcl_Init(interp) == TCL_ERROR ) {
        fprintf(stderr, "Tcl_Init failed: %s\n", interp->result);
        exit(1);
    }

    if( Tk_Init(interp) == TCL_ERROR ) {
        fprintf(stderr, "Tk_Init failed: %s\n", interp->result);
        exit(1);
    }

    /* register your own commands */
    Tcl_CreateCommand( interp, "getSumExample", getSumExampleCmd,
        (ClientData) NULL, (void (*) ()) NULL);


    mainWindow = Tk_MainWindow(interp);

    Tcl_LinkVar( interp, "alive", ( char * )&alive, TCL_LINK_INT );
    Tcl_LinkVar( interp, "share2", ( char * )&share2, TCL_LINK_INT );

    retcode = Tcl_EvalFile( interp, "simple.tk" );

    if(retcode != TCL_OK) {
        fprintf(stderr, "\nGUI: Initialization ERROR: ");
        fprintf(stderr, "%s\n", interp->result);
        exit(1);
    }

    /* main loop */

    do {

        Tcl_DoOneEvent(TK_DONT_WAIT);

        /* illustrate activity occuring between C and GUI */
        share2++;
        if( share2 == 1000000 )
            {
            share2 = 0;
            }

        } while( alive == 1 );


    return 0;

}

/*

 *
 * Get sum example command 
 *
 */

int getSumExampleCmd _ANSI_ARGS_((ClientData clientData,

    Tcl_Interp *interp, int argc, char **argv))

{

    double      var1;
    double      var2;

    /* get passed parameters to sum */

    if( Tcl_GetDouble( interp, argv[1], &var1 ) != TCL_OK )
        {
        return TCL_ERROR;
        }

    if( Tcl_GetDouble( interp, argv[2], &var2 ) != TCL_OK )
        {
        return TCL_ERROR;
        }

    sprintf( interp->result, "%f", var1+var2 );
    return TCL_OK ;

}


-----------------cut and name file "simple.tk"----------------------------

# # Super simple example of Tk + C # Tcl/Tk script file # Michael K. Ganley # [email protected] # 20 January 1997 #

option add *Entry.cursor gumby option add *Button.highlightThickness 0 option add *Frame.highlightThickness 0 option add *Entry.highlightThickness 0 option add *Button.borderWidth 1

# # configTop # Procedure to show toplevel window and set some attributes # proc configTop {} {

    global color
    global tkVersion
    global tk_strictMotif

    wm positionfrom . user
    wm sizefrom . program
    wm geometry . 320x100+20+10
    wm maxsize . 400 300
    wm minsize . 100 100
    wm title . {Ganley's "simple2" example}

    . configure -background $color(bg)

}

# # main Tk procedure # proc mainProc {} {

    global color
    global fonts
    global alive
    global var
    global share2

    button .kill \
    -bg $color(bg) \
    -text {Quit} \
    -font $fonts(2) \
    -command {set alive 0}

    button .add \
    -bg $color(bg) \
    -text {Add} \
    -font $fonts(2) \
    -command {addProc}

    entry  .e1 \
     -relief {flat} \
     -bg $color(bg2) \
     -font $fonts(2) \
     -textvariable var(1)  

    entry  .e2 \
     -relief {flat} \
     -bg $color(bg2) \
     -font $fonts(2) \
     -textvariable var(2)  

    entry  .e3 \
     -relief {flat} \
     -bg $color(bg) \
     -font $fonts(2) \
     -textvariable var(3) \
     -state disabled

    entry  .e4 \
     -relief {flat} \
     -bg $color(bg) \
     -font $fonts(2) \
     -textvariable share2 \
     -state disabled

    place .kill -x 5 -y 5 -width 100 -height 20 -anchor nw
    place .add -x 5 -y 30 -width 100 -height 20 -anchor nw
    place .e1 -x 110 -y 30 -width 50 -height 20 -anchor nw
    place .e2 -x 162 -y 30 -width 50 -height 20 -anchor nw
    place .e3 -x 215 -y 30 -width 50 -height 20 -anchor nw  
    place .e4 -x 5 -y 55 -width 50 -height 20 -anchor nw    

}

# # Add variables by calling C function # proc addProc {} {

    global var

    set result [getSumExample $var(1) $var(2)]
    set temp [format "%-.3f" $result]
    set var(3) "= $temp"

}

# # Initialize variables # proc initGlobals {} {

    global color
    global fonts 
    global alive
    global var
    global share2

    set color(bg) gray70
    set color(bg2) gray50
    set fonts(2) "-Adobe-Helvetica-medium-R-Normal--*-100-*"
    set alive 1
    set var(1) 0.0
    set var(2) 0.0

}

# # Read C's shared variable "share2" every half second # And schedule other stuff if you desire # proc running {} {

    global share2

    # force update of e4's textvariable
    set share2 $share2

    after 500 [ list running ]

}

# # Invoke to begin # initGlobals configTop mainProc running

# eof #


-----------------cut and name file "makefile" ---------------------------

# Makefile # Change of paths may be needed - no specific compiler options # may need some tweeking for your system. # # Michael K. Ganley # [email protected] # 20 January 1997 # #

# You may replace the *.so stuff with *.a stuff instead # if you have all of the *.a libraries. CC = gcc -g LINKER = $(CC) LIBS = /usr/lib/libtk.so \

                        /usr/lib/libtcl.so \
                        /usr/X11R6/lib/libX11.so 

# -ldl is needed for *.so libraries.

LLIBS = -ltk -ltcl -lm -ldl

# Flags CFLAGS = -I/usr/local/include \

                        -I/usr/X11/include \
                        -I/usr/src/tk \
                        -I/usr/src/tcl 

COFLAGS = -q LDFLAGS = -I/usr/X11/include \

                        -I/usr/src/tk \
                        -I/usr/src/tcl

all: simple

simple: simple.o libtk.so

        $(CC) -o simple simple.o $(LDFLAGS) $(LIBS) $(LLIBS)

libtk.so :

clean:

        rm -f simple *.o