Hello all.
I want to build an object on top of a canvas. The object adds some internationalized features. I'm not clear how to manage the XOTcl object in conjunction with the Tk object. For now, I'm just managing the two as separate entities.
Icanvas icanvas .f ;# I pass the path for the tk object. pack .f.icanvas -fill both -expand true ;# And manipulate the tk object with tk commands.
Or maybe I should:
pack [icanvas tkpath] -fill both -expand true
Or give my object a truly wicked name:
Icanvas .f.icanvas ;# Will this work?
Or wrap every tk command in my xotcl object.
What is your thinking regarding widgets from XOTcl?
Regards,
Rick
"Rick Hedin" wrote:
Hello all.
I want to build an object on top of a canvas. The object adds some internationalized features. I'm not clear how to manage the XOTcl object in conjunction with the Tk object. For now, I'm just managing the two as separate entities.
Icanvas icanvas .f ;# I pass the path for the tk object. pack .f.icanvas -fill both -expand true ;# And manipulate the tk object with tk commands.
Or maybe I should:
pack [icanvas tkpath] -fill both -expand true
Or give my object a truly wicked name:
Icanvas .f.icanvas ;# Will this work?
Or wrap every tk command in my xotcl object.
What is your thinking regarding widgets from XOTcl?
I have a data structure registering object names for tk widgets. Thus, a tk callback looks generally like:
::bind $path <tk event> { set object [names object %W] $object method args }
(names is an XOtcl Object knowing which object a tk widget belongs to)
-- Catherine Letondal -- Pasteur Institute Computing Center
On Mon, 5 Feb 2001, Rick Hedin wrote:
What is your thinking regarding widgets from XOTcl?
I've been pondering the same issue, but I haven't yet required Tk so I haven't done anything about it. Anyway, the ideas I came up with follow on these lines:
1) Have a meta-class for Tk widgets, that automatically registers a filter for each class it creates. This filter would reroute all calls to an object to the actual Tk widget so that when "$myButton configure" is called the command ".frame.b configure" is called. Then with this meta-class created, just create the classes for each Tk object (not really that many -- and no methods are needed for the XOTcl classes as methods are just passed on).
2) Do the same with [incr Tk]. In fact, [incr Tcl] is enough. Then you automatically can use [incr Tk] and all other iTcl libraries as if they were XOTcl libraries. Could be extremely handy.
- ---------- = = ---------//--+ | / Kristoffer Lawson | www.fishpool.fi|.com +-> | setok@fishpool.com | - - --+------ |-- Fishpool Creations Ltd - / | +-------- = - - - = --------- /~setok/
"RH" == Rick Hedin rhedin@aquifer.geology.uiuc.edu writes:
RH> Hello all.
RH> I want to build an object on top of a canvas. The object adds RH> some internationalized features. I'm not clear how to manage the RH> XOTcl object in conjunction with the Tk object. For now, I'm just RH> managing the two as separate entities.
RH> Icanvas icanvas .f ;# I pass the path for the tk object. RH> pack .f.icanvas -fill both -expand true ;# And manipulate the tk object RH> with tk commands.
RH> Or maybe I should: RH> pack [icanvas tkpath] -fill both -expand true
RH> Or give my object a truly wicked name: RH> Icanvas .f.icanvas ;# Will this work?
yes, if the intention is that the Tk widget instance has the name ".f". but i would not recommend to determine from the XOTcl object name the name of the Tk widget.
RH> Or wrap every tk command in my xotcl object.
Sometimes, this is a straight forward solution to keeps the XOTcl objects and the tk widget in separate trees. Architecturally, this is not a beauty.
RH> What is your thinking regarding widgets from XOTcl?
For now, we have not definite answer. You might check the following solution, that is conceptionally quite simple. For each "XOTcl Widget" an tk object with a leading dot is created. It handles [self], xotcl methods, instance variables and should be easy extensible for most purposes.
best regards -gustaf =====================================================================
#!/usr/local/bin/xowish
# make generation of tk widgets easy configurable Class parameter tk
# Widget is a metaclass, that provides the generic create method to # the Widget classes. For each XOTcl object, a Tk widget with a # leading dot is created. Class Widget -superclass Class Widget instproc create {name args} { eval [[self] set tk] .$name; next }
# The Class TkWidget handles the flags, that are useful to redefine # for XOTcl. We want to be able to work with self in callbacks, we # want to sent instances variables of Objects, and so on. Everything # unknown is delegated to Tk configure. Widget TkWidget TkWidget instproc s {} {string trimleft [self] :} TkWidget instproc invoke cmd { eval $cmd } TkWidget instproc command cmd { .[[self] s] configure -[self proc] [list [self] invoke $cmd] } TkWidget instproc textvariable v { .[[self] s] configure -[self proc] [self]::$v } TkWidget instproc unknown {m args} { puts stderr "UNKNOWN eval .[[self] s] $args" eval .[[self] s] configure -$m $args }
# we want to support the following widget classes Widget Button -superclass TkWidget -tk button Widget Label -superclass TkWidget -tk label Widget Entry -superclass TkWidget -tk entry
# well, now our application: Button hello -text "hello world" -command {[self] text [self]} Label l -text "Enter some text:" Entry e -width 20 -textvariable input Button quit -text "exit" -command {[self] print} pack .hello .l .e .quit
quit proc print {} { puts "entry var: '[e set input]'" exit }
Gustaf Neumann wrote:
RH> Or wrap every tk command in my xotcl object.
Sometimes, this is a straight forward solution to keeps the XOTcl objects and the tk widget in separate trees. Architecturally, this is not a beauty.
How do you then implement the composite pattern for widgets trees as explained in:
G. Neumann, U. Zdun: Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages, in: Proceedings of COOTS, San Diego, California, USA, May, 1999.
In my application, every Tk widget creation is wrapped in a method:
widgets build ${frame}::widgets::panel { frame $path.panel }
where widgets is of class Object.
Then you may store informations concerning the widget, in order to be able to save it, clone it, or whatever.
The composite pattern is very convenient indeed for tk widgets. I use it to make recursive Tk bindings, or to build a graphical attribute editor for all the widget tree.
-- Catherine Letondal -- Pasteur Institute Computing Center
"CL" == Catherine Letondal letondal@pasteur.fr writes:
CL> Gustaf Neumann wrote: RH> Or wrap every tk command in my xotcl object.
Sometimes, this is a straight forward solution to keeps the XOTcl objects and the tk widget in separate trees. Architecturally, this is not a beauty.
CL> How do you then implement the composite pattern for widgets trees as CL> explained in:
... CL> In my application, every Tk widget creation is wrapped in a method: CL> widgets build ${frame}::widgets::panel { CL> frame $path.panel CL> } CL> where widgets is of class Object.
my point is not that you can't do it, the point is that it can be done in many ways, but we have for now no definitive best solution. The main problem is that often there are other Tcl commands (pure Tcl, [incr tcl], tk, ...) that we want to treat like first class XOTcl objects. A mechanism suited for Tk is not necessarly the best for [incr tcl] or other situations. We are using some ad-hoc approaches for the problem already for "package" (see package.xotcl) or file (see make.xotcl) based on renaming of the original command. The classical solution are object wrappers for "legacy components", which are more a programming than a generic approach, and are difficult when the "legacy component" has a different understanding of e.g. the composite model (like tk). I have implemented most of my GUIs via Motif, which is some respects easier to integrate, since it follows the idea "every widget has an ID" rather than "every widget is a command" (like in tk). The latter leads to the "conflict" with XOTcl, which says "every Object is a command". OTOH, solving this conflict is quite an interesting and generic challenge.
CL> Then you may store informations concerning the widget, in order to CL> be able to save it, clone it, or whatever.
CL> The composite pattern is very convenient indeed for tk widgets. I CL> use it to make recursive Tk bindings, or to build a graphical CL> attribute editor for all the widget tree.
Catherine, you seem to be quite happy with your Tk integration. Can you post a small but complete introductory example. Do you use Tk features like "-command"?
best regards -gustaf
CL> -- CL> Catherine Letondal -- Pasteur Institute Computing Center
On Tue, 6 Feb 2001, Gustaf Neumann wrote:
understanding of e.g. the composite model (like tk). I have implemented most of my GUIs via Motif, which is some respects easier to integrate, since it follows the idea "every widget has an ID" rather than "every widget is a command" (like in tk). The latter leads to the "conflict" with XOTcl, which says "every Object is a command". OTOH, solving this conflict is quite an interesting and generic challenge.
Well would it be possible with the method I suggested using filters and a TkClass metaclass? This only required that you have basically a header file which makes the equivalent TkClass instances. The filter can operate so that it creates the Tk commands in a separate namespace so as not to conflict. It then just passes the XOTcl methods directly to the Tk command. Some specific XOTcl methods could be added too like "pack" or "update".
I believe this would be quite a neat solution. It requires very little work then to wrap a Tk "class" into a new XOTcl class, and the objects feel like real XOTcl objects in every sense. Even better: this same solution can be used for ITcl and other object-like things that need to be wrapped in XOTcl.
- ---------- = = ---------//--+ | / Kristoffer Lawson | www.fishpool.fi|.com +-> | setok@fishpool.com | - - --+------ |-- Fishpool Creations Ltd - / | +-------- = - - - = --------- /~setok/
Gustaf Neumann wrote:
Catherine, you seem to be quite happy with your Tk integration. Can you post a small but complete introductory example. Do you use Tk features like "-command"?
Yes I do, as well as -variable -textvariable and bindings. I use [incr tk] as well (for which I have to help the Xotcl widgets tree to correspond to the actual tk tree).
The aim was to be able to keep the actual tk creation/layout code that you can borrow in books, ftp sites, application examples, ... it's very important to me to keep such examples usable without any adaptation.
Another aim is to be able to have a memory image of the Tk widgets state, for I want my application to be persistent, or just to be able to edit or clone objects with their tk widgets.
A 3rd goal is to keep advantages of the composite pattern. For instance, as the general idea of the application (very influenced by the Self environment although much more modest) is to have a graphical handle for application objects (I don't mean all XOtcl objects, but application level ones), I need to be able to find this object from a menu which may be posted from any location in the GUI.
So I will try to summarize a small example - it's impossible to make it complete though, there is too much code and it's not ready for distribution - at all.
# ----------------------------------------------------------------------------- # composite pattern
[... same as in the Xotcl paper...] Composite AbstractNode AbstractNode filter compositeFilter AbstractNode abstract instproc iterate v
# ----------------------------------------------------------------------------- # GraphObject is the general graphical object class
GraphObject instproc draw args { [...]
# generic frame for all graphical objects
set frame ${object_name}_frame widgets build $frame { frame $path -borderwidth 2 -relief sunken } widgets layout $frame { pack $path -expand 1 -fill both }
# location for custom widgets (as in [incr tk]) [self] instvar childsite set childsite ${frame}::widgets [...] }
# ----------------------------------------------------------------------------- # example: a field object # (containing an entry widget and a button)
Class Field -superclass GraphObject
Field instproc init args { [...] [self] draw }
Field instproc draw args { next
[self] instvar childsite set path [$childsite set path] widgets build $childsite { frame $path } widgets layout $childsite { pack $path -expand 1 -fill both }
# ------------------------------------------------------------- # 1st tk widget: an entry
[self] instvar data # datavar contains the name of a global variable set datavar [$data set datavar] widgets build ${childsite}::datafield { entry $path.datafield -textvariable $datavar } widgets layout ${childsite}::datafield { pack $path.datafield -side top -expand 1 -fill x } ::bind $path.datafield <Return> { set object [names object %W] # MVC protocol [$object set data] update }
# ------------------------------------------------------------- # 2nd tk widget: a button
widgets build ${childsite}::doit { button $path.doit -command [list [self] do_something] -text "DoIt" } widgets layout ${childsite}::doit { pack $path.doit -side left }
# -------------------------------------------------------------
# connect all widgets to the current graphical object $childsite iterate setObjectName [self]
# bind button3 to a "meta" menu for all the widgets hierarchy $childsite iterate bindMetaButton
}
# ----------------------------------------------------------------------------- # Widgets
Class Widgets -superclass AbstractNode Class Widget -superclass Widgets
Object widgets
widgets proc build {widget body} {
# XOtcl Widget creation uplevel Widget $widget
# actual tk creation if [catch {set path [uplevel $body]} err] { global errorInfo puts stderr "widgets (build) err:$err\n$errorInfo" } else { [self] setwidget $widget $path } }
widgets proc setwidget {widget path} {
# data structure initializations $widget set path $path $widget set type [string tolower [winfo class $path]] $widget set options [[self] buildoptions $path] }
widgets proc layout {widget body} {
# actual layout if [catch {uplevel $body} err] { global errorInfo puts stderr "Widget (layout) err:$err\n$errorInfo" } else {
# data structure initializations... $widget set layout [[self] buildlayout [$widget set path]] } }
# ----------------------------------------------------------------------------- # visitors for widgets hierarchy
Class TreeVisitor TreeVisitor abstract instproc visit objectName
# menu for graphical objects
TreeVisitor bindMetaButton bindMetaButton proc visit args { set node [lindex $args 0] set path [$node set path] if [::winfo exists $path] { ::bind $path <ButtonPress-3> { set object [names object %W] ${object}::menu display $object [$object set commands] %x %y %X %Y %W break } } }
TreeVisitor setObjectName setObjectName proc visit args { set node [lindex $args 0] set obj [lindex $args 1] $node instvar object if { $obj != "" } { set object $obj } if { [names object [$node set path]] == "" } { names object [$node set path] $obj } }
# ----------------------------------------------------------------------------- # names: name server (alias, graphical objects, widgets,...)
Object names
# bind graphical objects and tk widgets names proc object {widget {object ""}} { [self] instvar objects if {$object == ""} { if [info exists objects($widget)] { [self] set objects($widget) } } else { [self] set objects($widget) $object } }
-- Catherine Letondal -- Pasteur Institute Computing Center