How to convert the python Tkinter listbox into Tcl/Tk? - tcl

How to convert the following listbox python code in to Tcl/Tk?
from tkinter import *
root = Tk()
root.title("Dude0")
root.geometry("400x400")
my_listbox = Listbox(root)
my_listbox.pack(pady=15)
root.mainloop()
Seems like all the examples for tk are for python these days instead of TCL.

Here is the translation:
package require Tk
wm title . "Dude0"
wm geometry . "400x400"
listbox .my_listbox
pack .my_listbox -pady 15
With wish you automatically get a root window named ".", and wish will automatically listen for events so you don't need to call the equivalent of mainloop. For other widgets such as your listbox, you need to give them a path that uses "." as separators. So .my_listbox represents a child of the root window. You can assign that to a variable, but in my experience it's good enough to just give the widgets themselves user-friendly names.
Most other things that are methods in tkinter will be procs in tcl, and kwargs in tkinter are option/value pairs in tcl (options begin with a dash). So instead of my_listbox.pack(padx=15), in tcl you would do pack .my_listbox -padx 15.
tkdocs.com has an excellent tutorial that lets you see examples written in python, tcl, ruby, and perl.

I don't know if my transcription of your python code will help you, but I'm agree with #GlennJackman, tkdocs will be more interesting than my response... that said, the code written in Tcl :
package require Tk ; # from tkinter import *
set root .root
toplevel $root ; # root = Tk()
wm title $root "Dude0" ; # root.title("Dude0")
wm geometry $root "400x400" ; # root.geometry("400x400")
listbox $root.lb ; # my_listbox = Listbox(root)
pack $root.lb -pady 15 ; # my_listbox.pack(pady=15)

Related

set tcl a variable from gui

I want to get file name from gui. I wrote a code like below.
I am able to run all the scripts for once time. what i am looking for when i select the file form hwtk::openfileentry, i want to set a variable for the filename.
After i selected the file, if i run "set filename [$win.op1 get]" i am able to get the name. However i need automate this, i want to trigger the varible after selecting file from gui.
Best Regards
set win .window
catch {destroy $win}
toplevel $win -class TopClass
wm title $win "Tools"
wm geometry $win 420x200+100+150
wm resizable $win 1 1
wm deiconify $win
label $win.01 -text "openmodel"
place $win.01 -x 0 -y 10 -width 130 -height 32
hwtk::openfileentry $win.op1
place $win.op1 -x 135 -y 10 -width 250 -height 32
set filename [$win.op1 get]
According to the documentation, hwtk::openfileentry takes a -command option to specify a user callback script. I would imagine, based on normal usage for things Tk, that that might the place to trigger reading from the widget and writing to the variable:
proc updateTheFilename {window variable} {
# Double quotes just because of Stack Overflow's highlighting
upvar "#0" $variable v
set v [$window get]
}
# Forming callbacks like this is very much a best practice; least surprising in complex scenarios
hwtk::openfileentry $win.op1 -command [list updateTheFilename $win.op1 filename]

pass a string which contains variables to a proc in tcl, without evaluation

I want to pass a string to a proc which contains variables, without evaluating/substituting the value of the variable for example :
% set intf "blah"
% set cmd "show router interface $intf"
% dummy_proc $cmd
the requirement is that, the $cmd that dummy_proc receives should be "show router interface $intf" and not "show router interface blah"
I am looking for answers which do not involve the following :
using a backslash for the $ => \$
wrapping the string in curly braces {}
I'd appreciate any help with this. Thanks
The problem is that Tcl uniformly substitutes those bits before you procedure gets them; it's how the language is defined to operate. The sole extra piece of information you can get is this (if your version of Tcl is new enough):
proc example {cmd} {
puts call=[dict get [info frame -1] cmd]
puts cmd=$cmd
}
set intf "blah"
set cmd "show router interface $intf"
example $cmd
which will print:
call=example $cmd
op=show router interface blah
The setting of cmd is already over and done with at the point you get to inspect.
The way you'd solve this with slightly freer requirements is:
proc example {cmd} {
puts "supplied: $cmd"
# Do the substitutions as in "double quotes" *in the caller's context*
set cmd [uplevel 1 [list subst $cmd]]
puts "substituted: $cmd"
}
set intf "blah"
set cmd {show router interface $intf}
example $cmd
which prints:
supplied: show router interface $intf
substituted: show router interface blah
You cannot solve this without delaying the substitution of $intf until the evaluation of the procedure, and that requires either braces or the (ugly) strategies listed in the other answers. Tcl style genuinely encourages the use of braces for this sort of thing, and double quotes always mean that variables (and command calls) inside are to be substituted immediately. Delay that substitution (which you have the tools for) and you can substitute at the moment you need.
Simple. For example, you could use one of these:
set cmd "show router interface \x24intf"
set cmd [format "show router interface $%s" intf]
append cmd "show router interface " $ intf
set cmd [string cat "show router interface " $ intf]
But I expect that isn't what you wanted either.
Tcl provides an eminently simple and expressive way to specify a minimally-substituted string:
set cmd {show router interface $intf}
This has the advantages of clarity and of not complicating the interpreter with exceptions from the straightforward evaluation rules that Tcl uses.
Documentation:
Summary of Tcl language syntax
There are lots of ugly alternatives to using braces, for example:
set cmd [string map "% $" "show router interface %intf"]
set cmd [join [list "show router interface $" "intf"] ""]
set cmd [format "show router interface %sintf" $]
set cmd "show router interface [set $ $]intf"
set cmd $; set cmd "show router interface [set cmd]intf"
set cmd "show router interface [lindex $ 0]intf"
Why you would want to use these alternatives instead of braces is a mystery.

TCL : what is the default package for tcl commands

I want to know in which package all tcl commands will be available .
for example string , list etc .
When we want to use expect , we will use Expect package , similarly we are using these (string , list etc ...) commands without importing any package . i want to know in which package these are all belong ?
basically I came from java ... In java "java.lang" package default.
Formally, all commands that form the core of the Tcl language are provided by the Tcl package. That package is required for you before you run any code (and has to be; the package command itself is one of those commands). By historical convention, the large majority of Tcl commands are placed in the global namespace, which is on the command resolution path of all namespaces. (It's logically last on the path unless explicitly set with namespace path.) Some Tcl commands are defined in the ::tcl namespace, including a fair number of internal commands, direct access to which are not supported (if it isn't documented, it isn't supported; some are explicitly not supported but are relatively well known nonetheless; they're in the ::tcl::unsupported namespace). The namespace ::oo (and its children) are reserved for TclOO.
Commands defined by other packages — especially any newly-created packages — should be placed in a namespace with the same name as the package. This is merely a convention, and is not followed in older packages (particularly those that predate the namespace mechanism, such as Tk and TclX) because it is reckoned to be more important to maintain backward compatibility with existing scripts, but you will definitely find it easiest if you follow it. Also, it's usually the convention that the global namespace belongs principally to the user-defined application, despite the degree of pollution from other packages; it's yours to mangle as you see fit.
The exported commands of a namespace (which should typically be the public commands of the package with the same name) can be made available in another namespace without qualification via namespace import:
namespace eval ::foo {
proc grill {} { puts "grill!" }
namespace export grill
}
namespace eval ::bar {
namespace import ::foo::grill
grill
puts [namespace which grill]; # Prints ::bar::grill
puts [namespace origin grill]; # Prints ::foo::grill
}
Alternatively (from Tcl 8.5) you can update the resolution path of a namespace so it also looks in the other namespace:
namespace eval ::foo {
proc grill {} { puts "grill!" }
}
namespace eval ::bar {
namespace path ::foo
grill
puts [namespace which grill]; # Prints ::foo::grill
puts [namespace origin grill]; # Prints ::foo::grill
}
Note that the two mechanisms are a bit different: with imported commands, there is a local delegate for the command (and as that delegate is actually a command, you can rename it, etc.) whereas with path changes there are no such delegates; the command in the originating namespace is located directly during resolution of what grill means in that context.
List and strings does not come under any special packages. They are the basic commands. All the variables are treated as a string in tcl.
$ tclsh
% set l [list 1 2 3 4 5]
1 2 3 4 5
% lappend l 6
1 2 3 4 5 6
% set str "Hello, World"
Hello, World

Finding the type of a Tk widget

Is there a way to know what is the "type" of a Tk widget?
As an example, let's suppose I create a label, using the tk::label command or the ttk::label command.
After that, I just have the path name of the widget, for example .l. Now, I'd like to know what was the command used to build .l.
What I need is a programmatic solution, some code that given the .l path can return the name of the command, and I'm interested in Tcl solutions, or even Tcl extensions coded in C.
A way to do this could be renaming all the widget creation commands with procs that save that information somewhere and then does exactly what the original command would do, but this solution requires that you know all the available widget creation commands, and doesn't take into account user defined widget (or megawidgets as a whole).
Thank you very much for your help.
The winfo class command will tell you the class of a widget, which is usually good enough (see this interactive session):
% label .tklabel; puts [winfo class .tklabel]
Label
% ttk::label .ttklabel; puts [winfo class .ttklabel]
TLabel
Note that you can set the class of standard Tk toplevels and Ttk widgets at creation time. This can make things rather complex. With toplevels, you can see whether [winfo toplevel $w] eq $w is true, but that's not a guaranteed test from 8.5 onwards, as it is possible to reparent toplevels as children of another widget or turn classic frames into toplevels (via wm forget/wm manage).
If you have to get the exact command used to create a widget, the only truly sure method is to trap the creation command and log the info, like this:
rename frame the_real_frame
proc frame {pathName args} {
set ::creationInfo($pathName) [list frame $args]
the_real_frame $pathName {*}$args
}
It's usually easier to try to avoid such complexity (especially as in a production setting you'll also need to set things up to deal with <Destroy> events so that you clean up information about no-longer-extant widgets, and that just adds lots more trickiness).

How to run tcl script inside other tcl script?

I have two tcl scripts. I want to run the second script when the first finished. How can I do it?
Depends on what do you really mean.
One way is to write a third ("master") script which would do
source /the/path/to/the/first.tcl
source /the/path/to/the/second.tcl
Another way is to just add the second call to source from the above example to the bottom of the first script.
Amendment to the first approach: if the scripts to be executed are located in the same directory as the master script, an idiomatic way to source them is
set where [file dirname [info script]]
source [file join $where first.tcl]
source [file join $where second.tcl]
This way sourcing will work no matter what the current process's directory is and where the project directory is located.
While this is generally a correct answer, because the question was not precisely formulated there are tons of ways to achieve the goal of running Tcl code from within Tcl.
I want to get into this in detail because understanding the execution of code is one major point in understanding Tcl itself.
There is source
The source command should not be confound with executing scripts in a classical way, what I think the thread starter has asked.
The source command is like the "include" command in c/perl/php.
Languages like java or python on the other hand only have "import" mechanisms.
The difference is that those languages create a internal database of available packages, who are linked to the corresponding source/binary/bytecode files. By writing a import statement, linked source or bytecode or binary files are loaded. This allows more in-depth dependency management without writing additional code.
In Tcl this can be achieved with namespaces and the package require command.
Example:
Suppose you have this source.tcl:
proc foo {bar} {puts "baz"}
set BAM "BOO"
Now, you have your "master" script like you call it. I call it "main". It has the content:
set BAM {my important data}
source source.tcl
#also the function foo can now be used because the source reads the whole script
foo {wuz}
set BAM
#will output "BOO"
The exec command
If you can live with additional overhead of starting a whole new interpreter instance you could also do:
set BAM {my important data}
exec tclsh source.tcl
#The variable BAM will not be modified. You can not use the function foo.
The eval command
The command eval can evaluate a string or a list (in Tcl everything is a string) like it would be programmed code.
You would have to load the complete source file to a string. And then use eval, to evaluate the code within a separate scope, to not overwrite stuff in your main source file.
set fp [open "somefile" r]
set code_string [read $fp]
close $fp
eval $code_string
You just need to use source to run the 2nd script.
source "/tmp/whatever.tcl"
Simplest possible working example I could find:
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ tclsh main.tcl
hello world
7
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ cat main.tcl
lappend auto_path /home/thufir/NetBeansProjects/spawnTelnet/telnet/api
package require weather 1.0
tutstack::hello
set A 3
set B 4
puts [tutstack::sum $A $B]
#puts [tutstack::hello "fred"]
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ cat api/weather.tcl
package provide weather 1.0
package require Tcl 8.5
namespace eval ::tutstack {
}
proc ::tutstack::hello {} {
puts "hello world"
}
proc ::tutstack::sum {arg1 arg2} {
set x [expr {$arg1 + $arg2}];
return $x
}
proc ::tutstack::helloWorld {arg1} {
return "hello plus arg"
}
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$ cat api/pkgIndex.tcl
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
package ifneeded weather 1.0 [list source [file join $dir weather.tcl]]
thufir#dur:~/NetBeansProjects/spawnTelnet/telnet$