[color=red][b]参考资料:http://noyesno.net/page/82[/b][/color]
1. 什么是Tcl/Tk/Tix
Tcl是"Tool Command Language"的缩写,是一种解释型的脚本语言。Tcl的特殊之处在于Tcl解释器可以嵌入到C/C++程序中。Tcl有一个解释器的C语言函数库,可以通过调用这些函数在应用程序中实现Tcl的特性。正是因为有这个解释器的接口,Tcl可以与C混合编程,可以用C语言扩展Tcl的命令,而且C中的变量和Tcl中的变量可以互相访问。在第5部分将演示这一功能。因此,在EDA工具中,一般都集成了Tcl环境。
Tk是建立在Tcl语言基础上的窗口系统的程序包,Tk扩展了Tcl的指令,可以很容易的建立图形界面。Tk包括了实现图形界面的最基本单元如按钮、滚动条等。同样,Tk也可以集成到C语言中,也可以通过C来扩展Tk的功能。
Tix是Tk的扩展,是建立在Tk上的更高层的程序包,可以实现如文件选择对话框之类的操作。Tix也可以与C语言集成。
在Red Hat Linux中包含了Tcl, Tk, Tix套件。这些包的位置在:
/usr/share/tcl**
/usr/share/tk**
/usr/share/tixwish**
在命令行下,可以通过tclsh, wish, tixwish***来启动tcl, tk, tix解释器。
2. Tcl语法介绍
这里只对语法做简单介绍,其他可以参考[1]
Tcl实际上是面向字符串的语言,因此Tcl中的所有变量可以认为是字符串变量。为变量赋值:
% set a 4
4
% set b 5
5
在变量前加上$符号是引用这一变量。
因为所有变量都是字符串变量,所以以下语句是错误的、
% c = $a + $b
ambiguous command name "c": case catch cd clock close concat continue
正确的方式应该是:
% set c [expr $a+$b]
这里expr是求解$a+$b这一表达式的值。[]表示将expr的结果作为一个变量赋给c。
3. 用Tk构建图形界面
键入命令wish, 启动Tk解释器,会出现一个窗口,并出现%命令提示符。
以下给出几个例子并给出简单说明:
#!/usr/bin/wish -f
proc ad {a b} {
set res [expr $a + $b]
return $res
}
entry .a -width 6 -relief sunken -textvariable a
label .l1 -text "add"
entry .b -width 6 -relief sunken -textvariable b
label .l2 -text "is"
label .resul -textvariable result
button .bu1 -text compute
pack .a .l1 .b .l2 .resul .bu1 -side left -padx 1m -pady 2m
bind .bu1 <1> {set result [ad $a $b]}
这里proc定义了一个Tcl语言过程ad,输入参数为a, b,返回res。
这里entry定义了一个输入框,Tk的图形界面实际上是一个层次化的结构,这个层次化结构的根节点是.,因此.a表示的是跟下面的一个entry。同样.menubar.menu1表示的是菜单条中的一个菜单。-width指定了这个框的宽度为6,-relief指定了框的外观为sunken, -textvariable a指定这一个框对应一个字符串类型的变量a。label定义的是一个显示在图形界面中的字符串。这个字符串是"add"。button定义了一个按钮,这个按钮上的字符显示为"compute"。最后pack将这些对象显示到窗口中。-side left表示左对齐,-padx 1m -pady 2m表示x,y两个方向图形对象与边界的间距是1毫米和2毫米。
最后一句bind是表示事件的链接,这里意思是将.bu1的<l>事件对应到执行{set result [ad $a $b]}命令。<l>表示的是鼠标左键单击事件。这里在.bu1上单击左键,会更新result的值。ad $a $b是对ad过程的调用。
将上面的例子写入一个文件ex1.tcl,并chmod +x ex1.tcl,可以直接在命令行执行
$./ex1.tcl
4. 用Tix构建图形界面
在工作站上可以通过tixwish8.1.8.3来启动tix,会出现与tk同样的界面和提示符
下面是一个简单的例子:
#!/usr/bin/tixwish8.1.8.3
tixControl .tt -label Number: -max 100 -min 0
.tt config -integer true -step 1
pack .tt
同样可以在命令行执行这一脚本。这里不再多作解释,可以参考/usr/share/doc/tix-8.1.4/docs/tix-book/tix.book.html
5. Tcl/Tk/Tix与C/C++混合编程
a. 需包含的include文件:
#include <tcl.h>
#include <tk.h>
#include <tix.h>
b. link选项:
-ltcl -ltk -ltix
c. 常用函数:
Tcl_Interp * Tcl_CreateInterp(): 创建一个Tcl解释器对象。Tcl_Interp是解释器对象。
Tcl_DeleteInterp(Tcl_Interp *interp): 删除Tcl解释器对象。
Tcl_Init(): 初始化Tcl。
Tk_Init(): 初始化Tk。
Tix_Init(): 初始化Tix。
Tcl_CreateCommand(): 通过C语言函数实现Tcl的一个命令。
Tcl_SetVar(): 设定Tcl中的变量值。
Tcl_GetVar(): 获得Tcl中的变量值。
Tcl_LinkVar(): 共享C与Tcl中的变量。
Tk_Main(): 在C语言中调用Tcl脚本的主函数。
Tcl_Eval(): 执行一个Tcl语句。
具体的参数及调用方法参考man <函数名>
d. 一个例子:
// test.c
#include <tcl.h>
#include <tk.h>
#include <stdlib.h>
#include <stdio.h>
int ad_proc(ClientData d, Tcl_Interp *interp, int argc, const char * argv[])
{
int a,b,c;
char res[20];
if(argc != 3)
{
abort();
return TCL_OK;
}
else
{
sscanf(argv[1],"%d",&a);
sscanf(argv[2],"%d",&b);
c = a+b;
sprintf(res, "%d", c);
strcpy(interp->result,res);
return TCL_OK;
}
}
int InitProc( Tcl_Interp *interp
{
int iRet;
// Initialize tk first
iRet = Tcl_Init( interp ;
if( iRet == TCL_ERROR)
{
fprintf( stderr, "Unable to Initialize Tcl: %s\n",interp->result);
return( iRet ;
} // end if
iRet = Tk_Init(interp);
if(iRet == TCL_ERROR)
{
fprintf(stderr,"Unable to Initialize TK: %s\n",interp->result);
}
// iRet = Tix_Init(interp);
// if(iRet == TCL_ERROR)
// {
// fprintf(stderr,"Unable to Initialize Tix: %s\n", interp->result);
// }
Tcl_CreateCommand(interp,"ad",ad_proc,(ClientData)0,0);
return( TCL_OK ;
} // end InitProc
int main()
{
// declare an array for two strings
char *ppszArg[2];
// allocate strings and set their contents
ppszArg[0] = (char *)malloc( sizeof( char * 20 ;
ppszArg[1] = (char *)malloc( sizeof( char * 20 ;
strcpy( ppszArg[0], "test" ;
strcpy( ppszArg[1], "./ex1.tcl";
// the following call does not return
Tk_Main( 2, ppszArg, InitProc ;
free(ppszArg);
}
这个程序调用了上一节的Tcl脚本ex1.tcl,但是通过C语言来实现其中的ad过程。因此需要在ex1.tcl将以下部分注释:
#proc ad {a b} {
# set res [expr $a + $b]
# return $res
#}
这一程序中,main函数中的Tk_Main是调用Tcl脚本的主函数。这一函数的第一个参数表示ppszArg中变量的个数,这里的ppszArg第一个元素表示调用这一程序编译后执行程序的名称,第二个元素表示要执行的tcl脚本。第三个参数是一个初始化函数的指针。Tk_Main会首先调用这一个初始化函数。这一初始化函数,通过Tcl_Init()和Tk_Init()来初始化Tcl和Tk。Tcl_Init和Tk_Init执行成功会返回TCL_OK,否则返回TCL_ERROR,错误信息在Tcl_Interp结构的result参数中。在这一初始化函数中,调用了Tcl_CreateCommand函数将ex1.tcl中的一个过程用C语言的ad_proc函数来实现。这一函数的第一个参数是Tcl解释器指针,"ad"表示Tcl中调用这一过程的调用名称,ad_proc是指向实现这一过程的C语言函数的指针,后两个参数这里为默认值(ClientData) 0和0。在ad_proc C语言函数中,其标准形式为int ad_proc(ClientData d, Tcl_Interp *interp, int argc, const char * argv[])。这里argc, argv是Tcl中调用时传过来的参数。运算结果通过Tcl_Interp *interp解释指针的result参数传回。
通过gcc -o test -ltcl -ltk -ltix test.c来编译这一程序。
e. 一个简单的Tcl/Tk解释器:
以下程序实现了一个简单的Tcl/Tk解释器:
#include <tcl.h>
#include <tk.h>
#include <stdio.h>
#include <stdlib.h>
int InitProc( Tcl_Interp *interp
{
int iRet;
// Initialize tk first
iRet = Tcl_Init( interp ;
if( iRet == TCL_ERROR)
{
fprintf( stderr, "Unable to Initialize Tcl: %s\n",interp->result);
return( iRet ;
} // end if
iRet = Tk_Init(interp);
if(iRet == TCL_ERROR)
{
fprintf(stderr,"Unable to Initialize TK: %s\n",interp->result);
}
Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit);
return( TCL_OK ;
} // end InitProc
int main(int argc, char * argv[])
{
Tk_Main(argc, argv, InitProc ;
}
这里通过Tcl_CreateInterp函数创建一个解释器对象,并通过Tcl_Eval执行Tcl语句。Tcl_Init()和Tk_Init()函数用于初始化Tcl/Tk环境。
1. 什么是Tcl/Tk/Tix
Tcl是"Tool Command Language"的缩写,是一种解释型的脚本语言。Tcl的特殊之处在于Tcl解释器可以嵌入到C/C++程序中。Tcl有一个解释器的C语言函数库,可以通过调用这些函数在应用程序中实现Tcl的特性。正是因为有这个解释器的接口,Tcl可以与C混合编程,可以用C语言扩展Tcl的命令,而且C中的变量和Tcl中的变量可以互相访问。在第5部分将演示这一功能。因此,在EDA工具中,一般都集成了Tcl环境。
Tk是建立在Tcl语言基础上的窗口系统的程序包,Tk扩展了Tcl的指令,可以很容易的建立图形界面。Tk包括了实现图形界面的最基本单元如按钮、滚动条等。同样,Tk也可以集成到C语言中,也可以通过C来扩展Tk的功能。
Tix是Tk的扩展,是建立在Tk上的更高层的程序包,可以实现如文件选择对话框之类的操作。Tix也可以与C语言集成。
在Red Hat Linux中包含了Tcl, Tk, Tix套件。这些包的位置在:
/usr/share/tcl**
/usr/share/tk**
/usr/share/tixwish**
在命令行下,可以通过tclsh, wish, tixwish***来启动tcl, tk, tix解释器。
2. Tcl语法介绍
这里只对语法做简单介绍,其他可以参考[1]
Tcl实际上是面向字符串的语言,因此Tcl中的所有变量可以认为是字符串变量。为变量赋值:
% set a 4
4
% set b 5
5
在变量前加上$符号是引用这一变量。
因为所有变量都是字符串变量,所以以下语句是错误的、
% c = $a + $b
ambiguous command name "c": case catch cd clock close concat continue
正确的方式应该是:
% set c [expr $a+$b]
这里expr是求解$a+$b这一表达式的值。[]表示将expr的结果作为一个变量赋给c。
3. 用Tk构建图形界面
键入命令wish, 启动Tk解释器,会出现一个窗口,并出现%命令提示符。
以下给出几个例子并给出简单说明:
#!/usr/bin/wish -f
proc ad {a b} {
set res [expr $a + $b]
return $res
}
entry .a -width 6 -relief sunken -textvariable a
label .l1 -text "add"
entry .b -width 6 -relief sunken -textvariable b
label .l2 -text "is"
label .resul -textvariable result
button .bu1 -text compute
pack .a .l1 .b .l2 .resul .bu1 -side left -padx 1m -pady 2m
bind .bu1 <1> {set result [ad $a $b]}
这里proc定义了一个Tcl语言过程ad,输入参数为a, b,返回res。
这里entry定义了一个输入框,Tk的图形界面实际上是一个层次化的结构,这个层次化结构的根节点是.,因此.a表示的是跟下面的一个entry。同样.menubar.menu1表示的是菜单条中的一个菜单。-width指定了这个框的宽度为6,-relief指定了框的外观为sunken, -textvariable a指定这一个框对应一个字符串类型的变量a。label定义的是一个显示在图形界面中的字符串。这个字符串是"add"。button定义了一个按钮,这个按钮上的字符显示为"compute"。最后pack将这些对象显示到窗口中。-side left表示左对齐,-padx 1m -pady 2m表示x,y两个方向图形对象与边界的间距是1毫米和2毫米。
最后一句bind是表示事件的链接,这里意思是将.bu1的<l>事件对应到执行{set result [ad $a $b]}命令。<l>表示的是鼠标左键单击事件。这里在.bu1上单击左键,会更新result的值。ad $a $b是对ad过程的调用。
将上面的例子写入一个文件ex1.tcl,并chmod +x ex1.tcl,可以直接在命令行执行
$./ex1.tcl
4. 用Tix构建图形界面
在工作站上可以通过tixwish8.1.8.3来启动tix,会出现与tk同样的界面和提示符
下面是一个简单的例子:
#!/usr/bin/tixwish8.1.8.3
tixControl .tt -label Number: -max 100 -min 0
.tt config -integer true -step 1
pack .tt
同样可以在命令行执行这一脚本。这里不再多作解释,可以参考/usr/share/doc/tix-8.1.4/docs/tix-book/tix.book.html
5. Tcl/Tk/Tix与C/C++混合编程
a. 需包含的include文件:
#include <tcl.h>
#include <tk.h>
#include <tix.h>
b. link选项:
-ltcl -ltk -ltix
c. 常用函数:
Tcl_Interp * Tcl_CreateInterp(): 创建一个Tcl解释器对象。Tcl_Interp是解释器对象。
Tcl_DeleteInterp(Tcl_Interp *interp): 删除Tcl解释器对象。
Tcl_Init(): 初始化Tcl。
Tk_Init(): 初始化Tk。
Tix_Init(): 初始化Tix。
Tcl_CreateCommand(): 通过C语言函数实现Tcl的一个命令。
Tcl_SetVar(): 设定Tcl中的变量值。
Tcl_GetVar(): 获得Tcl中的变量值。
Tcl_LinkVar(): 共享C与Tcl中的变量。
Tk_Main(): 在C语言中调用Tcl脚本的主函数。
Tcl_Eval(): 执行一个Tcl语句。
具体的参数及调用方法参考man <函数名>
d. 一个例子:
// test.c
#include <tcl.h>
#include <tk.h>
#include <stdlib.h>
#include <stdio.h>
int ad_proc(ClientData d, Tcl_Interp *interp, int argc, const char * argv[])
{
int a,b,c;
char res[20];
if(argc != 3)
{
abort();
return TCL_OK;
}
else
{
sscanf(argv[1],"%d",&a);
sscanf(argv[2],"%d",&b);
c = a+b;
sprintf(res, "%d", c);
strcpy(interp->result,res);
return TCL_OK;
}
}
int InitProc( Tcl_Interp *interp
{
int iRet;
// Initialize tk first
iRet = Tcl_Init( interp ;
if( iRet == TCL_ERROR)
{
fprintf( stderr, "Unable to Initialize Tcl: %s\n",interp->result);
return( iRet ;
} // end if
iRet = Tk_Init(interp);
if(iRet == TCL_ERROR)
{
fprintf(stderr,"Unable to Initialize TK: %s\n",interp->result);
}
// iRet = Tix_Init(interp);
// if(iRet == TCL_ERROR)
// {
// fprintf(stderr,"Unable to Initialize Tix: %s\n", interp->result);
// }
Tcl_CreateCommand(interp,"ad",ad_proc,(ClientData)0,0);
return( TCL_OK ;
} // end InitProc
int main()
{
// declare an array for two strings
char *ppszArg[2];
// allocate strings and set their contents
ppszArg[0] = (char *)malloc( sizeof( char * 20 ;
ppszArg[1] = (char *)malloc( sizeof( char * 20 ;
strcpy( ppszArg[0], "test" ;
strcpy( ppszArg[1], "./ex1.tcl";
// the following call does not return
Tk_Main( 2, ppszArg, InitProc ;
free(ppszArg);
}
这个程序调用了上一节的Tcl脚本ex1.tcl,但是通过C语言来实现其中的ad过程。因此需要在ex1.tcl将以下部分注释:
#proc ad {a b} {
# set res [expr $a + $b]
# return $res
#}
这一程序中,main函数中的Tk_Main是调用Tcl脚本的主函数。这一函数的第一个参数表示ppszArg中变量的个数,这里的ppszArg第一个元素表示调用这一程序编译后执行程序的名称,第二个元素表示要执行的tcl脚本。第三个参数是一个初始化函数的指针。Tk_Main会首先调用这一个初始化函数。这一初始化函数,通过Tcl_Init()和Tk_Init()来初始化Tcl和Tk。Tcl_Init和Tk_Init执行成功会返回TCL_OK,否则返回TCL_ERROR,错误信息在Tcl_Interp结构的result参数中。在这一初始化函数中,调用了Tcl_CreateCommand函数将ex1.tcl中的一个过程用C语言的ad_proc函数来实现。这一函数的第一个参数是Tcl解释器指针,"ad"表示Tcl中调用这一过程的调用名称,ad_proc是指向实现这一过程的C语言函数的指针,后两个参数这里为默认值(ClientData) 0和0。在ad_proc C语言函数中,其标准形式为int ad_proc(ClientData d, Tcl_Interp *interp, int argc, const char * argv[])。这里argc, argv是Tcl中调用时传过来的参数。运算结果通过Tcl_Interp *interp解释指针的result参数传回。
通过gcc -o test -ltcl -ltk -ltix test.c来编译这一程序。
e. 一个简单的Tcl/Tk解释器:
以下程序实现了一个简单的Tcl/Tk解释器:
#include <tcl.h>
#include <tk.h>
#include <stdio.h>
#include <stdlib.h>
int InitProc( Tcl_Interp *interp
{
int iRet;
// Initialize tk first
iRet = Tcl_Init( interp ;
if( iRet == TCL_ERROR)
{
fprintf( stderr, "Unable to Initialize Tcl: %s\n",interp->result);
return( iRet ;
} // end if
iRet = Tk_Init(interp);
if(iRet == TCL_ERROR)
{
fprintf(stderr,"Unable to Initialize TK: %s\n",interp->result);
}
Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit);
return( TCL_OK ;
} // end InitProc
int main(int argc, char * argv[])
{
Tk_Main(argc, argv, InitProc ;
}
这里通过Tcl_CreateInterp函数创建一个解释器对象,并通过Tcl_Eval执行Tcl语句。Tcl_Init()和Tk_Init()函数用于初始化Tcl/Tk环境。