I have felt that Python suffers from two serious admissions. One is an easily used GUI building tool. PAGE is an attempt to provide such a tool.
PAGE is a tool which helps to create GUI interfaces for use with Python programs. I find that I write a number of small programs in Python but find adding any kind of a GUI is a bit of a strain. Python ships with Tkinter which is an interface to the Tk package. But there are several drawbacks to day to day use. First of all there is no real documentation shipped with the product. Recently, Grayson's book "Python and Tkinter Programming", Manning, 2000 appeared and it does help considerably but there is a lot of good information there (>600 pages) that I don't have time to dig out on a continuous basis. I only want to process it once. The other problem is that there are no tools which will bury some of the Tkinter details. It is that tool lack that I have attempted to fill. Grayson's book made it possible.
PAGE is not an end-all, be-all tool, but rather one that attempts to ease the burden on the Python programmer. It is aimed at the user who will put up with a less-than-general GUI capability in order to get an easily generated GUI. It is a helper tool. It does not build an entire application but rather is aimed at building a single GUI window.
PAGE is based on Stewart Allen's Visual Tcl program. In fact, it is vTcl, with an additional module that generates Python code. And yes, it is written in Tcl! Why not? Tcl seems ideal for implementing this program and since Tcl/Tk is needed to run the GUI anyway, there is no additional software support required. Further, it leaves the door open to use the same techniques for GUI builders in other languages which support Tk. The disadvantage of using a Tcl implementation is that one is restricted to widget sets which are available to both Tcl and Python. That seems to mean Tix or Iwidgets and I had a problem with Iwidgets. Thus one cannot use BWidgets or Pmw. At some point soon, the program should be translated to Python.
A small point. I am so intimidated by programming language designers who won't include 'go to' in a programming language, I feel that I must apologize for its use in this document describing a programming tool. There must be a better way to organize the material than I have found.
I did change a number of things I think were bugs and there are several things that I ignored because I couldn't figure them out. I ignored all that stuff dealing with compound widgets because it is not my desire to build compound widgets using PAGE; the menu button for compounds has been removed. I am getting all my compound widgets from the Tix package. There is a new alpha level version that may correct some of the Visual Tcl problems, but it is too early to serve as a base for this code.
Note that the Mode switching from between TEST and EDIT is not used and has been removed from the program. The Tcl interpreter is good, but it can't handle functions written in Python. So you can see that I used only what I could figure out and exploit, and tried to leave all the other stuff intact.
Finally, I support only the placer geometry manager. In the past, I have worked with Visual Basic and the placer geometry manager seemed comfortable and got me results that I wanted. (As far as VB is concerned I find the V almost incredible and the B really putrid.) As further justification, Constantin Teodorescu also limited the Java generation to the placer geometry manager. It seems really natural with the drag and drop paradigm. One disadvantage is that some of the sizes will be wrong if fonts change. This is because several Tk widgets have sizing based on font parameters. This has implications if the GUI is generated with different fonts or resolution than are active during execution.
If you wish to change a GUI by opening in Visual Tcl an existing tcl file, Visual Tcl will source the specified file and change all the bindings for all the widgets to allow things like resizing, selection, deletion, etc. I never figured out how to manipulate bindings for itcl widgets and so I have excluded them from my consideration. I tried a question to the itcl newsgroup, but never got an answer. The key to the operation of Visual Tcl and PAGE is that the mouse bindings for the widgets can be changed so that you can drag them around, resize them, bring up special purpose menues, etc.
The mechanism for instantiating widgets is to generate tcl/tk code and execute it on the fly. Very nice indeed. It even allows some undo capability.
The power of Tcl/Tk makes it unnecessary to build a data base for the widgets and their attributes and bindings or worry about default settings. Tk does it all for you. It has handy primitives like 'widget configure' which coughs up all the attributes and their defaults for filling in the Attribute Editor fields so that the author only had to build a framework for constructing the Attribute Editor to take advantage of the Tk facilities. When the window/widget manipulation is completed Visual Tcl generates a true Tcl program. If you later want to modify the program all that is necessary is to 'source' the generated file and you are ready to carry on - an essential feature. When it comes to emitting code for functions, the 'body' primitive provides input token stream for the proc including '\n' characters. Event binding are easily handled with the 'bind' command.
Basically, all I had to do was write a few pages of code in one module to process a list of widgets known to Tcl/Tk, extract their attributes using the 'configure' primitive and put out calls to Tkinter. One can trivially tell whether an attribute differs from the default or not. Similarly, the 'bind' command give access to bindings set for widget events. It was easy to deal with subwidgets and parent widgets using 'parent' and 'subwidget' primitives. The Visual Tcl implementation contains a well designed global data structure using a small number of associative arrays which make it easy to add new widgets and manipulate widgets. Again, I found it very easy to understand and manipulate in spite of a nearly total lack of documentation.
This project has elevated Tcl in my esteem. All the primitives that I needed were available. Some touches are nice even in an unintended way. For instance, Visual Tcl adopted the convention of starting every procedure name with 'vTcl:' thereby avoiding any possibility of name clashes with Python since ':' is not a legal character of a Python name.
The one aspect of the Tk implementation that truly surprised me was that when a Tcl file is invoked by 'source' the syntax of a proc body is not analyzed. This means that it is possible when using Visual Tcl to specify functions with Python syntax or any other language. You can then save the Tcl file and source it. For me that meant that I could generate an interface in Visual Tcl including support functions written in Python and generate a Python program, go off and debug the generated program including the Python functions and then go back to Visual Tcl to update the interface and generate an updated Python program which preserved my changes to Python functions. All I had to do was write a very small utility to transfer the functions from the Python program back into the Tcl version.
Here is an example of a Tcl procedure with Python syntax:
proc {self.list_handler_2(self,} {} {
def list_handler_2(self, x):
index = self.lbox.curselection()
greeting(index)
The proc statement seems to be enough to get thru the 'source' operation
so that the 'body' command will yield:
def list_handler_2(self, x): index = self.lbox.curselection() greeting(index)At first, I thought this must be an old version of Tcl before they put in a compiler. I am running on Tcl 8.0 which is packaged with Python release 1.5.2 and the web site said the compiler was installed in 8.0. Later, I came to realize that this behavior is the consequence of the defined behavior of the Tcl 'proc' command. If so, then the approach that I took to generate Python interfaces could be used to generate code for any language that support interfaces to Tk.
I like the fact that there are many commands which with a proper argument string will commit a value and with fewer arguments will query status.
Finally, the process for placing a widget or changing its configuration is accomplished by generating a fragment of Tcl and executing it on the fly.
Lest you infer that I think Tcl is perfect, I feel that I would have gotten PAGE working quicker if Tcl had a source level debugger. I am always disappointed when language designers neglect to build in a decent debugger. This is especially true with interpreted languages where all the facilities are there for the hooking in a debugger. (I have had a similar conversation with Guido and may turn my attention in that direction next.) The only explanation that I can think of is that the authors are much better programmers than I am. That is certainly true of Ousterhout and van Rossum. In a similar vein, the Tcl trace back could be more easily interpreted by telling the user file and the line number from the top of the file and not an ofset from a branch point within a proc. I am willing to believe that the interpreter makes the sort of thing I want harder, but that's what computers are for. Of course, Don Libs has put a debugger in expect but it has never been picked up by the Tcl folks.
(I have just tried the TclPro debugger which recently went Open Source. Two interesting points with the TclPro debugger are (1) the debugger is slow. It's first step is to instrument the tcl modules constituting the program. It seems to involve a syntax analysis which probably takes half a minute or so with Page. Also, (2) the debugger doesn't work with Page, because the generated tcl modules contain functions with Python syntax. That's OK with the tcl interpreter because there is no attempt to execute them. However the TclPro debugger assumes that when such a file is 'sourced' the functions will be run so it does an analysis and barfs on the Python routines and halts. I think that is another indication that a debugger should be built into the tcl interpreter.)
The other thing I would like to see in Tcl/Tk is the adoption of more widgets. Tix, BWidgets, Pwm were all developed in answer to the same problem - the paucity of Tk widgets. Once shown the way, the Tk folks should have included them.
I found "Practical Programming in Tcl and Tk" by Brent B. Welch very helpful.
I had problems using Tix. For a while it appeared to have disappeared from the web, however, it turned up again on SourceForge.net. I spent much time getting many features of the TixNoteBook working. It seemed like a really nice widget, one that would conserve real estate in a GUI, so I persevered. I figured out a method to allow the PAGE user to change the number of pages in the tixNoteBook. Another widget I really wanted was a progress bar which is implemented in Tix, even though it's absent from the overall man page. Even worse, it is missing from PyTix package; I added it to PyTix, so take a look at my version of PyTix in the PAGE distribution. The meager documentation in Visual Tcl suggests that Tix plays undesirable games with fonts, colors, and so forth. You can see what happens when using Tix with PAGE, not all windows have the same fonts or even the same colors. Apparently this will be changed in the next release of Tix. I have modified Tix to avoid the problem through the use the TkoptionsDB file. In short, it attempts to read '~/python/TkoptionsDB' and if it finds it, I think that it will use them rather than the Tix option schemes. There is a later section about the options data base. I seemed to get it working correctly using 'Wheat' as the background color. I would have liked to include the tixPanedWindow in PAGE but I was unable to get it working correctly. The code which I experimented with is still in the package, in case someone is willing to look at it and tell me where I am wrong.
I believe that PAGE is currently useful, I have used it for several of my Python projects. It is time for some feed back. Clearly more widgets should be included. I have concentrated on ones that I think that I want to use.
PAGE supports many of the Tk widgets and many of the Tix widgets. In deference to my tired old eyes, I have enlarged the icons on the tool box of those widgets that I handle. The other widgets seem to be of lower priority to me. For instance, hooking up scroll bars to widgets confuses to me so I skipped it in favor of Tix scrolled widgets like scrolled list box, scrolled text box, and scrolled tree. (I really like trees. Use them all the time.) There seems to be no need for both horizontal and vertical scales since they differ by an attribute.
As mentioned above the TEST mode doesn't make much sense in a Python context and I have totally ignored the Compound menu. Also, I have done nothing with the Options menu other than play with the Bindings choice and I may have that wrong. I prefer to have aliases set within the attribute editor.
You may notice that the File menu is augmented to include an 'Open Py' choice. I will get into that later, for now it suffices to say that this is used when we want to modify a window that we have made and have already changed some of the python functions.
I have put a fair amount of time into providing the tixNotebook widget. Most of the desired function works. The pages inside the notebook appear to be frames but one cannot utilize all of the options of a frame. For instance, one cannot change the color of an individual page.
I would like to have supported the paned window, but I had problems. So it is not included in this release.
I have 'added' two new attributes. Tk, for instance, has a special attribute for specifying the action to be taken when a widget is selected. It is called 'command'. I imagine that they treat it differently from other actions because so many GUI operations depend on selecting a widget with Button-1. So, I felt that there are many widgets which require loading like list boxes, text boxes, etc., that I added for those widgets a 'loadcommand' attribute. Also added was bindcommand to make it easy to bind a command to Double-Button-1. I added 'bindcommand' before I fully understood the Bindings window which is supposedly a much more general mechanism for adding bindings. It is, except it doesn't appear to work with Tix subwidgets. So it is fortunate that I put in bind command.
PAGE is being made available because even in its current stage it is useful and I will concentrate on building a Python implementation but that will take considerable time. My TODO (unordered) list includes: the Python to tcl translator discussed below, add more widgets, figuring out the tixPanedWindow, improving the Widget Tree, improving menu placement in and out of the menubar, hook PAGE to the IDE, improving the documentation, improving the icons. Of this list, I will be doing the first item immediately.
Finally, let me say that my monitor resolution is set to 1024x768 and I have enlarged some of the icons and set the default fonts to make things more readable for me. Needless to say that when run with less resolution, things get pretty big.
The distribution is a single file, pageXXX.tgz. Just untar it in your home directory. All files will be put in /page. Put /page in your PATH environmental variable
The entry module for PAGE is /page/page.tcl. A shell script 'pg' invokes the program. Modify the assignments of the script variable to reflect where tixwish and PAGE are located and be sure it is executable. To start the program, execute the command 'pg'. If you supply a file name as the one allowable parameter, that file will be opened.
inc.py is a little utility that takes the functions from a '.py' file
and stuffs them into the corresponding '.tcl' file. It is incorporated
in the 'Open Py' file menu pick. Just let lie in the install
directory. I hope to replace this soon with a less confusing
alternative.
The steps for installing PAGE are:
The way I set up Tix was to download source files for Tcl, Tk, and Tix. Place all three tar files in a common directory called tix-tcl-tk. I then used unzip and tar to expand all three. In the subdirectory 'tix-8.1.1/docs', there are instruction for building Tix on several platforms. I followed the instructions in UnixInst.txt. As a final step, I made a symbolic link to couple tixwish and tixwish8.1.8.3. I installed the programs in the default location which is /usr/local/.
Briefly, the steps are make and install Tcl 8.3, make and install Tk 8.3, and finally make and install Tix 8.1.1. This three step procedure is smoothest if you are dealing with Tcl 8.3. The only thing that I ran into was the fact that the install.sh file in the top level of the Tix-8.1.1 directory has to be executable.
There is a tutorial text file for Visual Tcl in the doc directory. Go ahead and read it. Do the examples and then come back to here. Note that the tutorial guides you thru the generation of an entire Tcl/Tk project rather than just how to build a single GUI window as is the intent with PAGE, but it will give you a feel for the intent and use of Visual Tcl to construct individual windows.
One of the tutorial examples has the user building an example with two interacting windows. I use PAGE for building individual windows to be used by an encapsulating program. So there is a bit of emphasis change involved. I don't want to write my whole program using PAGE, just a GUI file that I import from the real application. That is, the basic function of PAGE is to facilitate the creation of individual GUI windows. It allows one to select widgets from a menu and place them in the window using the mouse. One can then modify the attributes of the widget, such as location and size, with the mouse and modify the other attributes with the Attribute Editor. Its operation is similar to that of VB. It is not meant for the creation of extremely sophisticated graphical presentations. Rather, it is for people like me; I find that Tkinter represents a body of knowledge that I found difficult to acquire, retain, and keep at my finger tips.
The way I use PAGE is to build a GUI module in Python that is very sparse and import that module in my application. The structure of the GUI module is very highly stylized. The PAGE package contains a fairly extravagant example, t1.tcl. As I was building PAGE, I added all the widgets to a single window. There are weird colors and font sizes to verify that I was able to change attributes of those widgets.
To see it, start PAGE, File->Open t1.py, depress Button-3 over the window and select Generate Python from the popup menu. You will get the following generated file without some of the annotations with multiple '#' characters which I added later.
To execute the generated Python module, just click on the Run button of the 'Python Window'. If you click on many of the widgets and menus thing will happen to show that there is a connection between the widget and the program. If you look at the code generated you will see various things to try. One to try is typing 'q' into the plum colored entry box. Stop the cursor over the scrolled listbox (the green one) or the IDE menu button to see examples of balloon help. Go through the pages of the notebook and press the demo button in the last page.
The block comments with three preceding #'s are annotations I added for this guide.
--------------------- beginning of t1.py ------------------------
#! /usr/bin/env python
# Generated by PAGE v 0.8
from Tkinter import *
import Tix, sys
root = Tix.Tk()
root.tk.call('load','','Tix')
### A bunch of functions in alphabetic order used within the GUI.
### Most are generated by the user. So far these are things
### like routines to load list boxes, update progress bars,
### and do stuff in response to mouse clicks, etc..
def greeting(str):
import Dialog
Dialog.Dialog(title="greetings",
text=str,
bitmap="",default=0,strings=("cont",))
def init():
pass
def load_listbox(o):
for i in range(50):
o.insert(END, i)
def load_scrolled_text(o):
o.insert(END, "\n1. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n2. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n3. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n4. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n5. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n6. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n7. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n8. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n9. This is a long bit of text that I want to put inside" + " this text box.")
o.insert(END, "\n0. This is a long bit of text that I want to put inside" + " this text box.")
def load_tree(o):
o.configure(separator="/")
o.add("/",text="/")
o.add("/home",text="home")
o.add("/home/ioi",text="ioi")
o.add("/home/foo",text="foo")
o.add("/usr",text="usr")
o.add("/usr/lib",text="lib")
o.add("/home/rozen", text="rozen")
o.add("/home/rozen/pkg", text="pkg")
o.add("/home/rozen/pkg/PyTix", text="PyTix")
o.add("/home/rozen/vp", text="vp")
o.add("/home/rozen/vp/lib", text='lib')
o.add("/usr/bin", text='bin')
o.add("/usr/man", text='man')
def open_file():
import tkFileDialog
tkFileDialog.askopenfilename(filetypes=[("all files", "*")])
def quit():
root.destroy()
def quit_a(event):
print 'quit_a: ' + event.type
quit()
def run_demo():
import time
for i in range(20):
x = (5.0 * (i+1)) /100
print "str(x) =", str(x)
w.tix34_tix31.configure(value=str(x))
w.tix34.update_idletasks()
time.sleep(.3)
def tree_browse(x):
greeting(str(x))
### The following class is the window. It is build by PAGE
class New_Toplevel_1:
def __init__(self, master=None):
self.fra17 = Frame (master)
self.fra17.place(in_=master,x=40,y=80)
self.fra17.configure(relief=GROOVE)
self.fra17.configure(background="green")
self.fra17.configure(borderwidth="2")
self.fra17.configure(height="75")
self.fra17.configure(relief="groove")
self.fra17.configure(width="125")
self.fra17_but18 = Button (self.fra17)
self.fra17_but18.place(in_=self.fra17,x=20,y=20)
self.fra17_but18.configure(activebackground="black")
self.fra17_but18.configure(activeforeground="ivory")
self.fra17_but18.configure(background="red")
self.fra17_but18.configure(command=quit)
self.fra17_but18.configure(font="helvetica 14 bold")
self.fra17_but18.configure(foreground="black")
self.fra17_but18.configure(text="Quit")
self.lab17 = Label (master)
self.lab17.place(in_=master,x=25,y=40)
self.lab17.configure(background="wheat")
self.lab17.configure(borderwidth="1")
self.lab17.configure(font="helvetica 14 bold")
self.lab17.configure(foreground="black")
self.lab17.configure(relief="raised")
self.lab17.configure(text="Don's Demo")
self.tex17 = Text (master)
self.tex17.place(in_=master,x=200,y=50)
self.tex17.configure(background="Wheat")
self.tex17.configure(font="helvetica 14 bold")
self.tex17.configure(foreground="black")
self.tex17.configure(height="8")
self.tex17.configure(insertbackground="black")
self.tex17.configure(selectbackground="black")
self.tex17.configure(selectforeground="ivory")
self.tex17.configure(width="20")
load_scrolled_text(self.tex17) # ldcmd .top17.tex17
self.ent17 = Entry (master)
self.ent17.place(in_=master,x=50,y=200)
self.ent17.configure(background="plum")
self.ent17.configure(font="helvetica 14 bold")
self.ent17.configure(foreground="black")
self.ent17.configure(insertbackground="black")
self.ent17.configure(selectbackground="black")
self.ent17.configure(selectforeground="ivory")
self.hello = StringVar()
self.ent17.configure(textvariable=self.hello)
self.ent17.configure(width="35")
self.ent17.bind('q',lambda e: greeting('q'))
self.fra19 = Frame (master)
self.fra19.place(in_=master,x=200,y=240)
self.fra19.configure(relief=GROOVE)
self.fra19.configure(background="wheat")
self.fra19.configure(borderwidth="4")
self.fra19.configure(height="115")
self.fra19.configure(relief="groove")
self.fra19.configure(width="125")
self.fra19_rad20 = Radiobutton (self.fra19)
self.fra19_rad20.place(in_=self.fra19,x=5,y=40)
self.fra19_rad20.configure(activebackground="black")
self.fra19_rad20.configure(activeforeground="ivory")
self.fra19_rad20.configure(background="wheat")
self.fra19_rad20.configure(command=lambda : greeting("Radio 2 "))
self.fra19_rad20.configure(font="helvetica 14 bold")
self.fra19_rad20.configure(foreground="black")
self.fra19_rad20.configure(selectcolor="red")
self.fra19_rad20.configure(text="radio 1")
self.fra19_rad22 = Radiobutton (self.fra19)
self.fra19_rad22.place(in_=self.fra19,x=5,y=75)
self.fra19_rad22.configure(activebackground="black")
self.fra19_rad22.configure(activeforeground="ivory")
self.fra19_rad22.configure(background="wheat")
self.fra19_rad22.configure(command=lambda : greeting("Radio 2 "))
self.fra19_rad22.configure(font="helvetica 14 bold")
self.fra19_rad22.configure(foreground="black")
self.fra19_rad22.configure(selectcolor="red")
self.fra19_rad22.configure(text="radio 2")
self.fra19_rad22.configure(value="2")
self.fra19_lab19 = Label (self.fra19)
self.fra19_lab19.place(in_=self.fra19,x=10,y=10)
self.fra19_lab19.configure(background="wheat")
self.fra19_lab19.configure(borderwidth="1")
self.fra19_lab19.configure(font="helvetica 14 bold")
self.fra19_lab19.configure(foreground="black")
self.fra19_lab19.configure(text="Radio Buttons")
self.fra18 = Frame (master)
self.fra18.place(in_=master,x=30,y=245)
self.fra18.configure(relief=GROOVE)
self.fra18.configure(background="wheat")
self.fra18.configure(borderwidth="4")
self.fra18.configure(height="110")
self.fra18.configure(relief="groove")
self.fra18.configure(width="125")
self.fra18_che20 = Checkbutton (self.fra18)
self.fra18_che20.place(in_=self.fra18,x=5,y=40)
self.fra18_che20.configure(activebackground="black")
self.fra18_che20.configure(activeforeground="ivory")
self.fra18_che20.configure(background="wheat")
self.fra18_che20.configure(command=lambda :greeting("Check Button 1"))
self.fra18_che20.configure(font="helvetica 14 bold")
self.fra18_che20.configure(foreground="black")
self.fra18_che20.configure(selectcolor="blue")
self.fra18_che20.configure(text="check 1")
self.fra18_che21 = Checkbutton (self.fra18)
self.fra18_che21.place(in_=self.fra18,x=5,y=75)
self.fra18_che21.configure(activebackground="black")
self.fra18_che21.configure(activeforeground="ivory")
self.fra18_che21.configure(background="wheat")
self.fra18_che21.configure(command=lambda :greeting("Check Button 2"))
self.fra18_che21.configure(font="helvetica 14 bold")
self.fra18_che21.configure(foreground="black")
self.fra18_che21.configure(selectcolor="blue")
self.fra18_che21.configure(text="check 2")
self.fra18_lab22 = Label (self.fra18)
self.fra18_lab22.place(in_=self.fra18,x=5,y=5)
self.fra18_lab22.configure(background="wheat")
self.fra18_lab22.configure(borderwidth="1")
self.fra18_lab22.configure(font="helvetica 14 bold")
self.fra18_lab22.configure(foreground="black")
self.fra18_lab22.configure(text="Check Buttons")
self.lis17 = Listbox (master)
self.lis17.place(in_=master,x=390,y=50)
self.lis17.configure(background="wheat")
self.lis17.configure(font="helvetica 14 bold")
self.lis17.configure(foreground="black")
self.lis17.configure(relief="raised")
self.lis17.configure(selectbackground="black")
self.lis17.configure(selectforeground="ivory")
load_listbox(self.lis17) # ldcmd .top17.lis17
self.lis17.bind('<Double-1>',self.list_handler) # bindcmd .top17.lis17
self.lis17.bind('<Button-3>',lambda e: quit_a(e))
self.sca17 = Scale (master)
self.sca17.place(in_=master,x=380,y=320)
self.sca17.configure(background="Wheat")
self.sca17.configure(font="helvetica 18")
self.sca17.configure(length="271")
self.sca17.configure(orient="horizontal")
self.sca17.configure(tickinterval="10.0")
self.tootsie = DoubleVar()
self.sca17.configure(variable=self.tootsie)
self.tix28 = Tix.LabelFrame(master)
self.tix28.place(in_=master,x=620,y=40)
self.tix28.configure(label="Outside Frame")
self.tix28.configure(background="red")
self.tix28.configure(borderwidth="2")
self.tix28.configure(highlightbackground="#d9d9d9")
self.tix28.configure(highlightcolor="Black")
self.tix28_border_frame = self.tix28.subwidget_list["frame"]
self.tix28_border_frame.configure(background="blue")
self.tix28_border_frame.configure(height="200")
self.tix28_border_frame.configure(width="150")
self.tix28_label = self.tix28.subwidget_list["label"]
self.tix28_label.configure(background="green")
self.tix28_label.configure(font="helvetica 18")
self.tix28_label.configure(relief="sunken")
self.tix28_label.configure(text="Outside Frame")
self.tix28_border_frame_tix29 = Tix.LabelFrame(self.tix28_border_frame)
self.tix28_border_frame_tix29.place(in_=self.tix28_border_frame,x=10,y=125)
self.tix28_border_frame_tix29.configure(label="Frame A")
self.tix28_border_frame_tix29.configure(background="wheat")
self.tix28_border_frame_tix29.configure(borderwidth="2")
self.tix28_border_frame_tix29.configure(highlightbackground="#d9d9d9")
self.tix28_border_frame_tix29.configure(highlightcolor="Black")
self.tix28_border_frame_tix29_border_frame = self.tix28_border_frame_tix29.subwidget_list["frame"]
self.tix28_border_frame_tix29_border_frame.configure(background="wheat")
self.tix28_border_frame_tix29_border_frame.configure(height="30")
self.tix28_border_frame_tix29_border_frame.configure(width="30")
self.tix28_border_frame_tix29_label = self.tix28_border_frame_tix29.subwidget_list["label"]
self.tix28_border_frame_tix29_label.configure(background="wheat")
self.tix28_border_frame_tix29_label.configure(font="helvetica 18")
self.tix28_border_frame_tix29_label.configure(text="Frame A")
self.tix28_border_frame_tix30 = Tix.LabelFrame(self.tix28_border_frame)
self.tix28_border_frame_tix30.place(in_=self.tix28_border_frame,x=20,y=25)
self.tix28_border_frame_tix30.configure(label="Frame B")
self.tix28_border_frame_tix30.configure(background="wheat")
self.tix28_border_frame_tix30.configure(borderwidth="2")
self.tix28_border_frame_tix30.configure(highlightbackground="#d9d9d9")
self.tix28_border_frame_tix30.configure(highlightcolor="Black")
self.tix28_border_frame_tix30_border_frame = self.tix28_border_frame_tix30.subwidget_list["frame"]
self.tix28_border_frame_tix30_border_frame.configure(background="wheat")
self.tix28_border_frame_tix30_border_frame.configure(height="44")
self.tix28_border_frame_tix30_border_frame.configure(width="105")
self.tix28_border_frame_tix30_label = self.tix28_border_frame_tix30.subwidget_list["label"]
self.tix28_border_frame_tix30_label.configure(background="wheat")
self.tix28_border_frame_tix30_label.configure(font="helvetica 18")
self.tix28_border_frame_tix30_label.configure(text="Frame B")
self.tix28_border_frame_tix30_border_frame_but29 = Button (self.tix28_border_frame_tix30_border_frame)
self.tix28_border_frame_tix30_border_frame_but29.place(in_=self.tix28_border_frame_tix30_border_frame,x=5,y=0)
self.tix28_border_frame_tix30_border_frame_but29.configure(background="pink")
self.tix28_border_frame_tix30_border_frame_but29.configure(command=quit)
self.tix28_border_frame_tix30_border_frame_but29.configure(font="helvetica 18")
self.tix28_border_frame_tix30_border_frame_but29.configure(text="exit")
self.tix29 = Tix.ScrolledListBox(master)
self.tix29.place(in_=master,x=410,y=440)
self.tix29.configure(background="wheat")
self.tix29.configure(highlightbackground="#d9d9d9")
self.tix29.configure(highlightcolor="Black")
self.tix29_listbox = self.tix29.subwidget_list["listbox"]
self.tix29_listbox.configure(background="#08db24")
self.tix29_listbox.configure(font="helvetica 18")
self.list_x = self.tix29_listbox
load_listbox(self.tix29_listbox) # ldcmd .top17.tix29.listbox
self.tix29_listbox.bind('<Double-1>',self.list_handler_2) # bindcmd .top17.tix29.listbox
self.lab30 = Label (master)
self.lab30.place(in_=master,x=420,y=400)
self.lab30.configure(background="wheat")
self.lab30.configure(borderwidth="1")
self.lab30.configure(font="helvetica 18")
self.lab30.configure(relief="raised")
self.lab30.configure(text="TixScrolledListBox")
self.lab30.configure(width="17")
self.tix31 = Tix.OptionMenu(master)
self.tix31.place(in_=master,x=50,y=370)
self.tix31.configure(label="OptionMenu: ")
self.tix31.configure(background="wheat")
self.tix31.configure(highlightbackground="#d9d9d9")
self.tix31.configure(highlightcolor="Black")
self.tix31.add_command("z_3",label="Option 1",underline=0)
self.tix31.add_command("z_4",label="Option 2",underline=0)
self.tix31.add_separator("z_5")
self.tix30 = Tix.LabelEntry(master)
self.tix30.place(in_=master,x=350,y=280)
self.tix30.configure(disabledforeground="#a3a3a3")
self.tix30.configure(label="LabelEntry:")
self.tix30.configure(background="wheat")
self.tix30.configure(highlightbackground="#d9d9d9")
self.tix30.configure(highlightcolor="Black")
self.tix30_frame_entry = self.tix30.subwidget_list["entry"]
self.tix30_frame_entry.configure(background="wheat")
self.tix30_frame_entry.configure(font="helvetica 18")
self.vu_file = StringVar()
self.tix30_frame_entry.configure(textvariable=self.vu_file)
self.tix30_frame_entry.configure(width="5")
self.tix30_label = self.tix30.subwidget_list["label"]
self.tix30_label.configure(background="wheat")
self.tix30_label.configure(font="Helvetica -18 bold")
self.tix30_label.configure(text="LabelEntry:")
self.tix32 = Tix.ComboBox(master,dropdown=1,editable=0,fancy=0)
self.tix32.place(in_=master,x=50,y=430)
self.tix32.configure(arrowbitmap="@/usr/local/lib/tix8.1/bitmaps/cbxarrow.xbm")
self.tix32.configure(crossbitmap="@/usr/local/lib/tix8.1/bitmaps/cross.xbm")
self.tix32.configure(disabledforeground="#a3a3a3")
self.tix32.configure(history="0")
self.tix32.configure(prunehistory="1")
self.tix32.configure(tickbitmap="@/usr/local/lib/tix8.1/bitmaps/tick.xbm")
self.tix32.configure(background="wheat")
self.tix32.configure(highlightbackground="#d9d9d9")
self.tix32.configure(highlightcolor="Black")
load_listbox(self.tix32) # ldcmd .top17.tix32
self.tix33 = Tix.Tree(master,options='\
hlist.background "pink"\
hlist.borderWidth "0"\
hlist.drawBranch "1"\
hlist.font "Helvetica -18 bold"\
hlist.highlightThickness "0"\
hlist.selectBackground "#c3c3c3"\
hlist.wideSelection "1"')
self.tix33.place(in_=master,x=690,y=300)
self.tix33.configure(browsecmd=lambda entry=None: tree_browse(entry))
self.tix33.configure(ignoreinvoke="0")
self.tix33.configure(scrollbar="auto")
self.tix33.configure(background="wheat")
self.tix33.configure(borderwidth="1")
self.tix33.configure(height="167")
self.tix33.configure(width="212")
self.T1 = self.tix33.subwidget_list['hlist']
load_tree(self.T1) # ldcmd .top17.tix33
self.tix33.autosetmode()
self.tix34 = Tix.NoteBook(master)
self.tix34.place(in_=master,x=40,y=490)
self.tix34.configure(background="wheat")
self.tix34.configure(height="213")
self.tix34.configure(highlightbackground="#d9d9d9")
self.tix34.configure(highlightcolor="Black")
self.tix34.configure(width="335")
self.tix34_nbframe = self.tix34.subwidget_list["nbframe"]
self.tix34_nbframe.configure(background="wheat")
self.tix34_nbframe.configure(font="helvetica 18")
self.tix34_nbframe.configure(inactivebackground="ivory")
self.tix34_nbframe.configure(relief="raised")
self.tix34_nbframe.configure(tabpadx="8")
self.tix34.add("page1",anchor="center",label="Page 1")
self.tix34.add("page2",anchor="center",label="Page 2")
self.tix34.add("page3",anchor="center",label="Page 3")
self.tix34.add("page4",anchor="center",label="Page 4")
self.page1 = self.tix34.subwidget_list["page1"]
self.tix34_nbframe_page1_but36 = Button (self.page1)
self.tix34_nbframe_page1_but36.place(in_=self.page1,x=20,y=65)
self.tix34_nbframe_page1_but36.configure(background="red")
self.tix34_nbframe_page1_but36.configure(command=quit)
self.tix34_nbframe_page1_but36.configure(font="helvetica 18")
self.tix34_nbframe_page1_but36.configure(text="So Long")
self.page2 = self.tix34.subwidget_list["page2"]
self.tix34_nbframe_page2_but38 = Button (self.page2)
self.tix34_nbframe_page2_but38.place(in_=self.page2,x=230,y=65)
self.tix34_nbframe_page2_but38.configure(background="green")
self.tix34_nbframe_page2_but38.configure(command=quit)
self.tix34_nbframe_page2_but38.configure(font="helvetica 18")
self.tix34_nbframe_page2_but38.configure(text="Good By")
self.page3 = self.tix34.subwidget_list["page3"]
self.tix34_nbframe_page3_but39 = Button (self.page3)
self.tix34_nbframe_page3_but39.place(in_=self.page3,x=210,y=120)
self.tix34_nbframe_page3_but39.configure(activeforeground="black")
self.tix34_nbframe_page3_but39.configure(background="Blue")
self.tix34_nbframe_page3_but39.configure(command=quit)
self.tix34_nbframe_page3_but39.configure(font="helvetica 18")
self.tix34_nbframe_page3_but39.configure(foreground="white")
self.tix34_nbframe_page3_but39.configure(text="Go Away")
self.page4 = self.tix34.subwidget_list["page4"]
self.tix34_nbframe_page4_tix30 = Tix.LabelFrame(self.page4)
self.tix34_nbframe_page4_tix30.place(in_=self.page4,x=5,y=5)
self.tix34_nbframe_page4_tix30.configure(label="label-me")
self.tix34_nbframe_page4_tix30.configure(background="wheat")
self.tix34_nbframe_page4_tix30.configure(borderwidth="2")
self.tix34_nbframe_page4_tix30.configure(highlightbackground="#d9d9d9")
self.tix34_nbframe_page4_tix30.configure(highlightcolor="Black")
self.tix34_nbframe_page4_tix30_border_frame = self.tix34_nbframe_page4_tix30.subwidget_list["frame"]
self.tix34_nbframe_page4_tix30_border_frame.configure(background="wheat")
self.tix34_nbframe_page4_tix30_border_frame.configure(height="108")
self.tix34_nbframe_page4_tix30_border_frame.configure(width="309")
self.tix34_nbframe_page4_tix30_label = self.tix34_nbframe_page4_tix30.subwidget_list["label"]
self.tix34_nbframe_page4_tix30_label.configure(background="wheat")
self.tix34_nbframe_page4_tix30_label.configure(font="helvetica 18")
self.tix34_nbframe_page4_tix30_label.configure(text="Progress Bar")
self.tix34_nbframe_page4_tix30_border_frame_tix31 = Tix.Meter(self.tix34_nbframe_page4_tix30_border_frame)
self.tix34_nbframe_page4_tix30_border_frame_tix31.place(in_=self.tix34_nbframe_page4_tix30_border_frame,x=130,y=40)
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(foreground="Black")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(value=".3")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(background="wheat")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(borderwidth="2")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(highlightbackground="#d9d9d9")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(highlightcolor="Black")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(relief="sunken")
self.tix34_nbframe_page4_tix30_border_frame_tix31.configure(width="150")
self.tix34_nbframe_page4_tix30_border_frame_but32 = Button (self.tix34_nbframe_page4_tix30_border_frame)
self.tix34_nbframe_page4_tix30_border_frame_but32.place(in_=self.tix34_nbframe_page4_tix30_border_frame,x=10,y=30)
self.tix34_nbframe_page4_tix30_border_frame_but32.configure(background="wheat")
self.tix34_nbframe_page4_tix30_border_frame_but32.configure(command=lambda : run_demo())
self.tix34_nbframe_page4_tix30_border_frame_but32.configure(font="helvetica 18")
self.tix34_nbframe_page4_tix30_border_frame_but32.configure(text="Demo")
self.tix35 = Tix.ScrolledText(master)
self.tix35.place(in_=master,x=660,y=530)
self.tix35.configure(background="wheat")
self.tix35.configure(borderwidth="1")
self.tix35.configure(height="141")
self.tix35.configure(highlightbackground="#d9d9d9")
self.tix35.configure(highlightcolor="Black")
self.tix35.configure(width="254")
self.tix35_text = self.tix35.subwidget_list["text"]
load_scrolled_text(self.tix35_text) # ldcmd .top17.tix35
self.tix35_text.configure(background="wheat")
self.tix35_text.configure(font="helvetica 18")
self.tix35_text.configure(takefocus="1")
self.tix35_text.configure(wrap="none")
self.tix36 = Tix.Meter(master)
self.tix36.place(in_=master,x=710,y=480)
self.tix36.configure(foreground="Black")
self.tix36.configure(value=".3")
self.tix36.configure(background="wheat")
self.tix36.configure(borderwidth="2")
self.tix36.configure(highlightbackground="#d9d9d9")
self.tix36.configure(highlightcolor="Black")
self.tix36.configure(relief="sunken")
self.tix36.configure(width="150")
self.menubar = Frame(master,relief=RAISED, bd=2)
self.menubar.pack(side=TOP,fill=X)
self.men18 = Menubutton(self.menubar, underline = 0)
self.men18.pack(side=LEFT)
self.men18.configure(text="File")
self.men18_m1 = Menu(self.men18)
self.men18_m1.add_command(label="Open",command=open_file,underline=0)
self.men18_m1.add_command(label="Close",command=lambda :greeting("close"),underline=0)
self.men18_m1.add_command(label="Exit",command=quit,underline=0)
self.men18['menu'] = self.men18_m1
self.men17 = Menubutton(self.menubar, underline = 0)
self.men17.pack(side=LEFT)
self.men17.configure(text="Edit")
self.men17_m2 = Menu(self.men17)
self.men17_m2.add_command(label="Cut",command=lambda:greeting("Cut"),underline=0)
self.men17_m2.add_command(label="Paste",command=lambda :greeting("Paste"),underline=0)
self.men17_m2.add_command(label="Copy",command=lambda : greeting("Copy"),underline=0)
self.men17_m2_cas2 = Menu(self.men17_m2)
self.men17_m2.add_cascade(label="Advanced",menu=self.men17_m2_cas2)
self.men17_m2_cas2.add_command(label="ToUpper",command=lambda :greeting("ToUpper"),underline=0)
self.men17_m2_cas2.add_command(label="ToLower",command=lambda : greeting("ToLower"),underline=0)
self.men17_m2.add_command(label="Delete",command=lambda : greeting("Delete"),underline=0)
self.men17['menu'] = self.men17_m2
self.men28 = Menubutton(self.menubar, underline = 0)
self.men28.pack(side=LEFT)
self.men28.configure(text="Font")
self.men28_m3 = Menu(self.men28)
self.men28_m3.add_checkbutton(label="Courier",command=lambda : greeting("Courier"))
self.men28_m3.add_checkbutton(label="Times Roman",command=lambda : greeting("Times Roman"))
self.men28_m3.add_checkbutton(label="Bodini Book",command=lambda : greeting("Bodini Book"))
self.men28['menu'] = self.men28_m3
self.men29 = Menubutton(self.menubar, underline = 0)
self.men29.pack(side=LEFT)
self.men29.configure(text="IDE")
self.men29_m4 = Menu(self.men29)
self.men29_m4.add_radiobutton(label="Emacs",command=lambda : greeting("Emacs"))
self.men29_m4.add_radiobutton(label="IDLE",command=lambda : greeting("IDLE"))
self.men29['menu'] = self.men29_m4
self.men23 = Menubutton(self.menubar, underline = 0)
self.men23.pack(side=RIGHT)
self.men23.configure(text="Help")
self.men23_m5 = Menu(self.men23)
self.men23['menu'] = self.men23_m5
self.balloon = Tix.Balloon(master)
self.balloon.bind_widget(self.tix29_listbox,balloonmsg="An example of balloon help message.")
self.balloon.bind_widget(self.men29,balloonmsg="Select the environemt that you wish to use.")
self.balloon.configure(bg='blue', borderwidth=3)
class New_Toplevel_1:
def __init__(self, master=None):
self.fra17 = Frame (master)
self.fra17.place(in_=master,x=40,y=80)
self.fra17.configure(relief=GROOVE)
self.fra17.configure(background="green")
self.fra17.configure(borderwidth="2")
self.fra17.configure(height="75")
self.fra17.configure(relief="groove")
self.fra17.configure(width="125")
self.fra17_but18 = Button (self.fra17)
self.fra17_but18.place(in_=self.fra17,x=20,y=20)
self.fra17_but18.configure(activebackground="black")
self.fra17_but18.configure(activeforeground="ivory")
self.fra17_but18.configure(background="red")
self.fra17_but18.configure(command=quit)
self.fra17_but18.configure(font="helvetica 14 bold")
self.fra17_but18.configure(foreground="black")
self.fra17_but18.configure(text="Quit")
self.lab17 = Label (master)
self.lab17.place(in_=master,x=25,y=40)
self.lab17.configure(background="wheat")
self.lab17.configure(borderwidth="1")
self.lab17.configure(font="helvetica 14 bold")
self.lab17.configure(foreground="black")
self.lab17.configure(relief="raised")
self.lab17.configure(text="Don's Demo")
self.tex17 = Text (master)
self.tex17.place(in_=master,x=200,y=50)
self.tex17.configure(background="Wheat")
self.tex17.configure(font="helvetica 14 bold")
self.tex17.configure(foreground="black")
self.tex17.configure(height="8")
self.tex17.configure(insertbackground="black")
self.tex17.configure(selectbackground="black")
self.tex17.configure(selectforeground="ivory")
self.tex17.configure(width="20")
load_scrolled_text(self.tex17) # ldcmd
self.ent17 = Entry (master)
self.ent17.place(in_=master,x=50,y=200)
self.ent17.configure(background="plum")
self.ent17.configure(font="helvetica 14 bold")
self.ent17.configure(foreground="black")
self.ent17.configure(insertbackground="black")
self.ent17.configure(selectbackground="black")
self.ent17.configure(selectforeground="ivory")
self.hello = StringVar()
self.ent17.configure(textvariable=self.hello)
self.ent17.configure(width="35")
self.ent17.bind('q',lambda e: greeting('q'))
self.fra19 = Frame (master)
self.fra19.place(in_=master,x=200,y=240)
self.fra19.configure(relief=GROOVE)
self.fra19.configure(background="wheat")
self.fra19.configure(borderwidth="4")
self.fra19.configure(height="115")
self.fra19.configure(relief="groove")
self.fra19.configure(width="125")
self.fra19_rad20 = Radiobutton (self.fra19)
self.fra19_rad20.place(in_=self.fra19,x=5,y=40)
self.fra19_rad20.configure(activebackground="black")
self.fra19_rad20.configure(activeforeground="ivory")
self.fra19_rad20.configure(background="wheat")
self.fra19_rad20.configure(command=lambda : greeting("Radio 2 "))
self.fra19_rad20.configure(font="helvetica 14 bold")
self.fra19_rad20.configure(foreground="black")
self.fra19_rad20.configure(selectcolor="red")
self.fra19_rad20.configure(text="radio 1")
self.fra19_rad22 = Radiobutton (self.fra19)
self.fra19_rad22.place(in_=self.fra19,x=5,y=75)
self.fra19_rad22.configure(activebackground="black")
self.fra19_rad22.configure(activeforeground="ivory")
self.fra19_rad22.configure(background="wheat")
self.fra19_rad22.configure(command=lambda : greeting("Radio 2 "))
self.fra19_rad22.configure(font="helvetica 14 bold")
self.fra19_rad22.configure(foreground="black")
self.fra19_rad22.configure(selectcolor="red")
self.fra19_rad22.configure(text="radio 2")
self.fra19_rad22.configure(value="2")
self.fra19_lab19 = Label (self.fra19)
self.fra19_lab19.place(in_=self.fra19,x=0,y=0)
self.fra19_lab19.configure(background="wheat")
self.fra19_lab19.configure(borderwidth="1")
self.fra19_lab19.configure(font="helvetica 14 bold")
self.fra19_lab19.configure(foreground="black")
self.fra19_lab19.configure(text="Radio Buttons")
self.fra18 = Frame (master)
self.fra18.place(in_=master,x=30,y=245)
self.fra18.configure(relief=GROOVE)
self.fra18.configure(background="wheat")
self.fra18.configure(borderwidth="4")
self.fra18.configure(height="110")
self.fra18.configure(relief="groove")
self.fra18.configure(width="125")
self.fra18_che20 = Checkbutton (self.fra18)
self.fra18_che20.place(in_=self.fra18,x=5,y=40)
self.fra18_che20.configure(activebackground="black")
self.fra18_che20.configure(activeforeground="ivory")
self.fra18_che20.configure(background="wheat")
self.fra18_che20.configure(command=lambda :greeting("Check Button 1"))
self.fra18_che20.configure(font="helvetica 14 bold")
self.fra18_che20.configure(foreground="black")
self.fra18_che20.configure(selectcolor="blue")
self.fra18_che20.configure(text="check 1")
self.fra18_che21 = Checkbutton (self.fra18)
self.fra18_che21.place(in_=self.fra18,x=5,y=75)
self.fra18_che21.configure(activebackground="black")
self.fra18_che21.configure(activeforeground="ivory")
self.fra18_che21.configure(background="wheat")
self.fra18_che21.configure(command=lambda :greeting("Check Button 2"))
self.fra18_che21.configure(font="helvetica 14 bold")
self.fra18_che21.configure(foreground="black")
self.fra18_che21.configure(selectcolor="blue")
self.fra18_che21.configure(text="check 2")
self.fra18_lab22 = Label (self.fra18)
self.fra18_lab22.place(in_=self.fra18,x=5,y=5)
self.fra18_lab22.configure(background="wheat")
self.fra18_lab22.configure(borderwidth="1")
self.fra18_lab22.configure(font="helvetica 14 bold")
self.fra18_lab22.configure(foreground="black")
self.fra18_lab22.configure(text="Check Buttons")
self.lis17 = Listbox (master)
self.lis17.place(in_=master,x=430,y=80)
self.lis17.configure(background="wheat")
self.lis17.configure(font="helvetica 14 bold")
self.lis17.configure(foreground="black")
self.lis17.configure(selectbackground="black")
self.lis17.configure(selectforeground="ivory")
load_listbox(self.lis17) # ldcmd
self.lis17.bind('',self.list_handler) # bindcmd
self.lis17.bind('',lambda e: quit_a(e))
self.sca17 = Scale (master)
self.sca17.place(in_=master,x=540,y=315)
self.sca17.configure(background="Wheat")
self.sca17.configure(font="helvetica 18")
self.sca17.configure(length="271")
self.sca17.configure(orient="horizontal")
self.sca17.configure(tickinterval="10.0")
self.tootsie = DoubleVar()
self.sca17.configure(variable=self.tootsie)
self.tix28 = Tix.LabelFrame(master)
self.tix28.place(in_=master,x=690,y=60)
self.tix28.configure(label="Outside Frame")
self.tix28.configure(background="red")
self.tix28.configure(borderwidth="2")
self.tix28.configure(highlightbackground="#d9d9d9")
self.tix28.configure(highlightcolor="Black")
tix28_frame = self.tix28.subwidget_list["frame"]
tix28_frame.configure(background="blue")
tix28_frame.configure(height="200")
tix28_frame.configure(width="150")
tix28_frame = self.tix28.subwidget_list["label"]
tix28_frame.configure(background="green")
tix28_frame.configure(font="helvetica 18")
tix28_frame.configure(relief="sunken")
tix28_frame.configure(text="Outside Frame")
self.f = self.tix28.subwidget_list["frame"]
self.tix28_tix29 = Tix.LabelFrame(self.f)
self.tix28_tix29.place(in_=self.f,x=10,y=125)
self.tix28_tix29.configure(label="Frame A")
self.tix28_tix29.configure(background="wheat")
self.tix28_tix29.configure(borderwidth="2")
self.tix28_tix29.configure(highlightbackground="#d9d9d9")
self.tix28_tix29.configure(highlightcolor="Black")
tix28_tix29_frame = self.tix28_tix29.subwidget_list["frame"]
tix28_tix29_frame.configure(background="wheat")
tix28_tix29_frame.configure(height="30")
tix28_tix29_frame.configure(width="30")
tix28_tix29_frame = self.tix28_tix29.subwidget_list["label"]
tix28_tix29_frame.configure(background="wheat")
tix28_tix29_frame.configure(font="helvetica 18")
tix28_tix29_frame.configure(text="Frame A")
self.f = self.tix28.subwidget_list["frame"]
self.tix28_tix30 = Tix.LabelFrame(self.f)
self.tix28_tix30.place(in_=self.f,x=20,y=25)
self.tix28_tix30.configure(label="Frame B")
self.tix28_tix30.configure(background="wheat")
self.tix28_tix30.configure(borderwidth="2")
self.tix28_tix30.configure(highlightbackground="#d9d9d9")
self.tix28_tix30.configure(highlightcolor="Black")
tix28_tix30_frame = self.tix28_tix30.subwidget_list["frame"]
tix28_tix30_frame.configure(background="wheat")
tix28_tix30_frame.configure(height="44")
tix28_tix30_frame.configure(width="105")
tix28_tix30_frame = self.tix28_tix30.subwidget_list["label"]
tix28_tix30_frame.configure(background="wheat")
tix28_tix30_frame.configure(font="helvetica 18")
tix28_tix30_frame.configure(text="Frame B")
self.f = self.tix28_tix30.subwidget_list["frame"]
self.tix28_but29 = Button (self.f)
self.tix28_but29.place(in_=self.f,x=5,y=0)
self.tix28_but29.configure(background="pink")
self.tix28_but29.configure(command=quit)
self.tix28_but29.configure(font="helvetica 18")
self.tix28_but29.configure(text="exit")
self.tix29 = Tix.ScrolledListBox(master)
self.tix29.place(in_=master,x=410,y=440)
self.tix29.configure(background="wheat")
self.tix29.configure(highlightbackground="#d9d9d9")
self.tix29.configure(highlightcolor="Black")
self.tix29_listbox = self.tix29.subwidget_list["listbox"]
self.tix29_listbox.configure(background="#08db24")
self.tix29_listbox.configure(font="helvetica 18")
self.list_x = self.tix29_listbox
load_listbox(self.tix29_listbox) # ldcmd
self.tix29_listbox.bind('',self.list_handler_2) # bindcmd
self.lab30 = Label (master)
self.lab30.place(in_=master,x=420,y=400)
self.lab30.configure(background="wheat")
self.lab30.configure(borderwidth="1")
self.lab30.configure(font="helvetica 18")
self.lab30.configure(relief="raised")
self.lab30.configure(text="TixScrolledListBox")
self.lab30.configure(width="17")
self.tix31 = Tix.OptionMenu(master)
self.tix31.place(in_=master,x=85,y=395)
self.tix31.configure(label="OptionMenu: ")
self.tix31.configure(background="wheat")
self.tix31.configure(highlightbackground="#d9d9d9")
self.tix31.configure(highlightcolor="Black")
self.tix31.add_command("z_3",label="Option 1",underline=0)
self.tix31.add_command("z_4",label="Option 2",underline=0)
self.tix31.add_separator("z_5")
self.tix30 = Tix.LabelEntry(master)
self.tix30.place(in_=master,x=100,y=515)
self.tix30.configure(disabledforeground="#a3a3a3")
self.tix30.configure(label="LabelEntry:")
self.tix30.configure(background="wheat")
self.tix30.configure(highlightbackground="#d9d9d9")
self.tix30.configure(highlightcolor="Black")
self.tix30_entry = self.tix30.subwidget_list["entry"]
self.tix30_entry.configure(background="wheat")
self.tix30_entry.configure(font="helvetica 18")
self.vu_file = StringVar()
self.tix30_entry.configure(textvariable=self.vu_file)
self.tix30_entry.configure(width="5")
self.tix30_label = self.tix30.subwidget_list["label"]
self.tix30_label.configure(background="wheat")
self.tix30_label.configure(font="Helvetica -18 bold")
self.tix30_label.configure(text="LabelEntry:")
self.tix32 = Tix.ComboBox(master,dropdown=1,editable=0,fancy=0)
self.tix32.place(in_=master,x=60,y=455)
self.tix32.configure(arrowbitmap="@/home/rgelpc254/rozen/lib/tix8.1/bitmaps/cbxarrow.xbm")
self.tix32.configure(crossbitmap="@/home/rgelpc254/rozen/lib/tix8.1/bitmaps/cross.xbm")
self.tix32.configure(disabledforeground="#a3a3a3")
self.tix32.configure(history="0")
self.tix32.configure(prunehistory="1")
self.tix32.configure(tickbitmap="@/home/rgelpc254/rozen/lib/tix8.1/bitmaps/tick.xbm")
self.tix32.configure(background="wheat")
self.tix32.configure(highlightbackground="#d9d9d9")
self.tix32.configure(highlightcolor="Black")
load_listbox(self.tix32) # ldcmd
self.tix33 = Tix.Tree(master,options='\
hlist.background "pink"\
hlist.borderWidth "0"\
hlist.drawBranch "1"\
hlist.font "Helvetica -18 bold"\
hlist.highlightThickness "0"\
hlist.selectBackground "#c3c3c3"\
hlist.wideSelection "1"')
self.tix33.place(in_=master,x=670,y=400)
self.tix33.configure(browsecmd=lambda entry=None: tree_browse(entry))
self.tix33.configure(ignoreinvoke="0")
self.tix33.configure(scrollbar="auto")
self.tix33.configure(background="wheat")
self.tix33.configure(borderwidth="1")
self.tix33.configure(height="167")
self.tix33.configure(width="212")
self.T1 = self.tix33.subwidget_list['hlist']
load_tree(self.T1) # ldcmd
self.tix33.autosetmode()
self.tix34 = Tix.NoteBook(master)
self.tix34.place(in_=master,x=40,y=550)
self.tix34.configure(background="wheat")
self.tix34.configure(height="213")
self.tix34.configure(highlightbackground="#d9d9d9")
self.tix34.configure(highlightcolor="Black")
self.tix34.configure(width="335")
self.nbf = self.tix34.subwidget_list["nbframe"]
self.nbf.configure(background="wheat")
self.nbf.configure(font="helvetica 18")
self.nbf.configure(inactivebackground="ivory")
self.nbf.configure(relief="raised")
self.nbf.configure(tabpadx="8")
self.tix34.add("page1",anchor="center",label="Page 1")
self.tix34.add("page2",anchor="center",label="Page 2")
self.tix34.add("page3",anchor="center",label="Page 3")
self.tix34.add("page4",anchor="center",label="Page 4")
self.page1 = self.tix34.subwidget_list["page1"]
self.tix34_but36 = Button (self.page1)
self.tix34_but36.place(in_=self.page1,x=20,y=65)
self.tix34_but36.configure(background="red")
self.tix34_but36.configure(command=quit)
self.tix34_but36.configure(font="helvetica 18")
self.tix34_but36.configure(text="So Long")
self.page2 = self.tix34.subwidget_list["page2"]
self.tix34_but38 = Button (self.page2)
self.tix34_but38.place(in_=self.page2,x=230,y=65)
self.tix34_but38.configure(background="green")
self.tix34_but38.configure(command=quit)
self.tix34_but38.configure(font="helvetica 18")
self.tix34_but38.configure(text="Good By")
self.page3 = self.tix34.subwidget_list["page3"]
self.tix34_but39 = Button (self.page3)
self.tix34_but39.place(in_=self.page3,x=210,y=120)
self.tix34_but39.configure(activeforeground="black")
self.tix34_but39.configure(background="Blue")
self.tix34_but39.configure(command=quit)
self.tix34_but39.configure(font="helvetica 18")
self.tix34_but39.configure(foreground="white")
self.tix34_but39.configure(text="Go Away")
self.page4 = self.tix34.subwidget_list["page4"]
self.tix34_tix30 = Tix.LabelFrame(self.page4)
self.tix34_tix30.place(in_=self.page4,x=5,y=5)
self.tix34_tix30.configure(label="label-me")
self.tix34_tix30.configure(background="wheat")
self.tix34_tix30.configure(borderwidth="2")
self.tix34_tix30.configure(highlightbackground="#d9d9d9")
self.tix34_tix30.configure(highlightcolor="Black")
tix34_tix30_frame = self.tix34_tix30.subwidget_list["frame"]
tix34_tix30_frame.configure(background="wheat")
tix34_tix30_frame.configure(height="108")
tix34_tix30_frame.configure(width="309")
tix34_tix30_frame = self.tix34_tix30.subwidget_list["label"]
tix34_tix30_frame.configure(background="wheat")
tix34_tix30_frame.configure(font="helvetica 18")
tix34_tix30_frame.configure(text="Progress Bar")
self.f = self.tix34_tix30.subwidget_list["frame"]
self.tix34_tix31 = Tix.Meter(self.f)
self.tix34_tix31.place(in_=self.f,x=130,y=40)
self.tix34_tix31.configure(foreground="Black")
self.tix34_tix31.configure(value=".3")
self.tix34_tix31.configure(background="wheat")
self.tix34_tix31.configure(borderwidth="2")
self.tix34_tix31.configure(highlightbackground="#d9d9d9")
self.tix34_tix31.configure(highlightcolor="Black")
self.tix34_tix31.configure(relief="sunken")
self.tix34_tix31.configure(width="150")
self.f = self.tix34_tix30.subwidget_list["frame"]
self.tix34_but32 = Button (self.f)
self.tix34_but32.place(in_=self.f,x=10,y=30)
self.tix34_but32.configure(background="wheat")
self.tix34_but32.configure(command=lambda : run_demo())
self.tix34_but32.configure(font="helvetica 18")
self.tix34_but32.configure(text="Demo")
self.tix35 = Tix.ScrolledText(master)
self.tix35.place(in_=master,x=660,y=630)
self.tix35.configure(background="wheat")
self.tix35.configure(borderwidth="1")
self.tix35.configure(height="141")
self.tix35.configure(highlightbackground="#d9d9d9")
self.tix35.configure(highlightcolor="Black")
self.tix35.configure(width="254")
self.tix35_text = self.tix35.subwidget_list["text"]
load_scrolled_text(self.tix35_text) # ldcmd
self.tix35_text.configure(background="wheat")
self.tix35_text.configure(font="helvetica 18")
self.tix35_text.configure(takefocus="1")
self.tix35_text.configure(wrap="none")
self.tix36 = Tix.Meter(master)
self.tix36.place(in_=master,x=685,y=580)
self.tix36.configure(foreground="Black")
self.tix36.configure(value=".3")
self.tix36.configure(background="wheat")
self.tix36.configure(borderwidth="2")
self.tix36.configure(highlightbackground="#d9d9d9")
self.tix36.configure(highlightcolor="Black")
self.tix36.configure(relief="sunken")
self.tix36.configure(width="150")
self.menubar = Frame(master,relief=RAISED, bd=2)
self.menubar.pack(side=TOP,fill=X)
self.men18 = Menubutton(self.menubar, underline = 0)
self.men18.pack(side=LEFT)
self.men18.configure(text="File")
self.men18_1 = Menu(self.men18)
self.men18_1.add_command(label="Open",command=open_file,underline=0)
self.men18_1.add_command(label="Close",command=lambda :greeting("close"),underline=0)
self.men18_1.add_command(label="Exit",command=quit,underline=0)
self.men18['menu'] = self.men18_1
self.men17 = Menubutton(self.menubar, underline = 0)
self.men17.pack(side=LEFT)
self.men17.configure(text="Edit")
self.men17_2 = Menu(self.men17)
self.men17_2.add_command(label="Cut",command=lambda:greeting("Cut"),underline=0)
self.men17_2.add_command(label="Paste",command=lambda :greeting("Paste"),underline=0)
self.men17_2.add_command(label="Copy",command=lambda : greeting("Copy"),underline=0)
self.men17_3 = Menu(self.men17_2)
self.men17_2.add_cascade(label="Advanced",menu=self.men17_3)
self.men17_3.add_command(label="ToUpper",command=lambda :greeting("ToUpper"),underline=0)
self.men17_3.add_command(label="ToLower",command=lambda : greeting("ToLower"),underline=0)
self.men17_2.add_command(label="Delete",command=lambda : greeting("Delete"),underline=0)
self.men17['menu'] = self.men17_2
self.men28 = Menubutton(self.menubar, underline = 0)
self.men28.pack(side=LEFT)
self.men28.configure(text="Font")
self.men28_3 = Menu(self.men28)
self.men28_3.add_checkbutton(label="Courier",command=lambda : greeting("Courier"))
self.men28_3.add_checkbutton(label="Times Roman",command=lambda : greeting("Times Roman"))
self.men28_3.add_checkbutton(label="Bodini Book",command=lambda : greeting("Bodini Book"))
self.men28['menu'] = self.men28_3
self.men29 = Menubutton(self.menubar, underline = 0)
self.men29.pack(side=LEFT)
self.men29.configure(text="IDE")
self.men29_4 = Menu(self.men29)
self.men29_4.add_radiobutton(label="Emacs",command=lambda : greeting("Emacs"))
self.men29_4.add_radiobutton(label="IDLE",command=lambda : greeting("IDLE"))
self.men29['menu'] = self.men29_4
self.men23 = Menubutton(self.menubar, underline = 0)
self.men23.pack(side=RIGHT)
self.men23.configure(text="Help")
self.men23_5 = Menu(self.men23)
self.men23['menu'] = self.men23_5
self.balloon = Tix.Balloon(master)
self.balloon.bind_widget(self.tix29_listbox,balloonmsg="An example of balloon help message.")
self.balloon.bind_widget(self.men29,balloonmsg="Select the environemt that you wish to use.")
self.balloon.configure(bg='blue', borderwidth=3)
### The following are user generated methods used in the GUI
### There is no difference between these and the global methods
### other than the user specified them by naming them specially.
### That is, the name specified in PAGE had 'self.' prepended.
def list_handler(self, x):
index = self.tix29_listbox.curselection()
greeting(index)
def list_handler_2(self, x):
index = self.list_x.curselection()
greeting(index)
### A generated function for starting the GUI.
### If you have stuff to add put it in init.
def vp_start_gui():
global w
root.title('New_Toplevel_1')
root.geometry('934x797+82+219')
w = New_Toplevel_1 (root)
init()
root.mainloop()
### The following is so that you can run the GUI stand alone and see
### what it looks like.
if __name__ == '__main__':
vp_start_gui()
When you are generating a GUI you are working with two files having the
same root name and extensions of tcl and py. For instance, if you are using
PAGE to build 'gui.py', then the file manipulated by PAGE is 'gui.tcl'.
Again, the example above involves 't1.tcl' and its companion 't1.py' When
you depress button 3 over the top level window, a popup menu will give
you the option to 'Generate Python' at which point the file 'gui.py' will
be generated and displayed in a new window. That window will allow you
save the py file or execute it, etc. You must exercise care to keep the
two files in sync to allow future changes. One way to do that, is to use
the menu item File->Save. Currently, PAGE is doing this for you. The first
time a save is attempted, the user will be asked to specify a name and
directory for storing the 'gui.tcl' file. (I am not too happy doing this
automatically because it some sense commits experimentation. However, when
the tcl file is saved, the previous version is renamed with the 'tcl.bak'
suffix.)
Often, you are not satisfied with the first Python file generated by PAGE. As I am debugging the GUI or extending the application, I will change the functions that appear in the py file and then I discover that I need an additional widget. At that point, I want to go back to PAGE to spruce up the GUI. I open PAGE and in the File menu I select 'Open Py', which invokes a utility, written in Python which merges any function or method changes from 'gui.py' into 'gui.tcl' before PAGE sources 'gui.tcl'. I then change the appearance of the GUI. When I then 'Generate Python' the new program 'gui.py' will have the new version of the GUI plus all of the debugging changes that had been made to the previous version of 'gui.py'.
Constantin Teodorescu added a special window for displaying and execution the java program that his code generates. I preserved this. But, a good tool of this variety should be coupled with an IDE. It was suggested to me by Guido that I should couple this with the Python IDE. And, of course, he is right. But PAGE should be translated to Python first and I would like to make it available before that is done. Further, I feel that EMACS is a fine IDE in general. It was not difficult to have PAGE use emacsclient for editing procedures and displaying the generated program. The option that enables that capability is labeled 'Use Emacsclient'.
Again, in deference to aged eyes I wish the Font Settings would change the fonts used in all the windows and menus but it doesn't; the program should work consistently with .Xdefaults or TkoptionDB files, but it doesn't. The program processes the preferences and records the stuff in the option data base. Then it calls lib_tix to initialize the tix behavior at which point tix goes off and set fonts and colors to stuff it likes and that are probably different than the previously created windows. Nothing worse than mixing two color schemes. So, after Tix mucks around with options, I come back in and read the TkoptionDB file and that overloads both the things Visual Tcl thinks I want and what Tix thinks is good for me; this is new and questionable code locatred in Tix.tcl. My TkoptionDB is included in the page directory. It's just two lines to set background colors to Wheat and the fonts to 18 point fonts. Again, using different fonts from the defaults can cause you some headaches if fonts for building differ from fonts for execution. I also saw similar problems related arising from trying to run a GUI which was generated on Linux on NT.
One has to be careful with the resolution that one uses when constructing a GUI. For instance, I made the mistake of creating the example GUI on a screen with the resolution set to 1024x768. If run on a screen with less resolution then the whole GUI will not fit inside the top level window and scroll bars are not provided.
Select the top-level window with Button-1 and then select the widget you would like to put in the top-level window. It will magically appear in the upper left hand corner of the top-level window. Again, use Button-1 to resize it and to move it to the desired location. When you select a widget, the Attribute Editor window will display all configuration options available for that widget and display the default values of those widgets. I think it is rather clear how to modify most of the options.
Things get more interesting when it comes to placing Tix megawidgets because they are collections of widgets and clicking Button-1 in the area of the widget may hit any one of the contained widgets. To move or resize a Megawidget it is necessary to grab the outer widget. This can be done by pressing Control-Button-1.
The final point about placing widgets is that some widgets are container widgets such as frame widgets and TixNamedFrame. You are allowed to place widgets inside of these widgets. That is done by selecting the container widget with Button-1 and then selecting the desired widget from the Widget Toolbar.
When you want to drag a Tix widget around or resize it, you have to be careful to get the top of the Tix. For instance, if the mouse is over the center of a TixScrolledListBox when you press Button-1 you don't select the TixScrolledListBox you select the listbox subwidget. Now that's fine if you want to change one of its attributes that you cannot change from the TixScrolledListBox attribute list. But it is not what you need to have selected to move or resize the TixScrolledListBox. To select the TixScrolledListBox move the mouse over any part of the TixScrolledListBox and press Control-Button-1. Modifying Attributes of Widgets
Specifying and modifying the the attributes with PAGE is very easy. All one has to do is to select the widget with Button-1 and then 'go to' the Attribute Editor and modify the attributes as desired. One can easily change the colors, fonts, labels, text, relief, and many that I don't even recognize.
There are different ways to change different things. Where there is limited list of choices, the change is selected from a drop down list. For colors one can type in the X color name, RGB in hex, or hit the little button next to the field and a color selection window appears. Labels and text fields can just be typed in. Where a command is specified, it can just be typed in or the button with ellipsis can be selected and a text window opens where the command can be entered. More on specifying command later.
Keep in mind: The generated Python module does respect the TkoptionDB file. So the executing Python program may appear slightly different from the PAGE template. In Tk many dimensions are in units of average character widths and thanks to Tix the PAGE fonts are of limited variation in size. So if you have specified a large font size in TkoptionDB, some of the widgets will be larger. Also, Tix will limit the color scheme so the window background will change from the Page template to generated GUI execution. Again, by using my TkoptionDB for both PAGE and the application encapsulating the finished GUI, I avoid both problems.
So, I use an alias which may be simpler to remember. So, as I am specifying attributes for the TixScrolledListBox, I also specify the alias should be 'list_x', the following line of code is generated:
self.list_x = self.tix29_listboxallowing me to write the event handler as:
def list_handler_2(self, x): index = self.list_x.curselection() greeting(index)Visual TCL as I got it allowed you to 'go to' the options menu and select Alias. At that point a window opens up to receive the alias. I changed the Attribute editor so that you can enter or change an alias there as well. Partly, I did things like that to convince myself that I was following what was going on.
lambda : foo(3)
not
foo(3)
Please see the examples above for command=... arguments.
The loadcommand event handling is very similar to the command event. In the above example, I used it to load the two list boxes with the same data. It was very convenient to pass to load_listbox the list to be loaded. In loading the first command, I actually put in the name of the object, 'self.lis17'. By the time I got to the TixScrolledListBox, I smartened up and specified '%me' as the object and the code generator converted that to the actual name of the object.
So much for the 'special' events. There is a whole group of events that can be linked to code. See the Tk man pages and Chapter 6 of Grayson,. They include responding to the different mouse button pressings or releases, a window getting or loosing focus, etc.. If you want to link code to one of those events, select the widget with Button-1, 'go to' the Options Menu and select Bindings. A Widget Binding window will open. I only recently began to figure this one out myself. The top line lets you specify the event. (As I got Visual TCL, things always blew up when you selected one of the last buttons because there were no entries behind them. I add a random few.) I believe the purpose of the Type entry field to the left is to enter the keys to which linkage is desired. (For instance in my t1.example, look at the entry field with the plum background. It responds to press the key 'q'). The multi-line entry below that is where you enter the command. As above, you want a one-line command, perhaps a lambda expression. There is a difference here, because when the event happens an argument 'e' is passed to the callback specifying the event. This means that the command is something like:
lambda e: foo_bar(1,3,5)I believe that the Bindings window is only partially completed. I am able to bind events to the simple Tk widgets, but have been unable to do so for Tix subwidgets. For instance, I don't see a way to bind a mouse event to the listbox subwidet of the TixScrolledListbox. Again, I hate to spend any time fixing Tix widgets when I should be concentrating on a Python version of PAGE.
Keep in mind: To add binding one works with the 'Widget Bindings' window. Consider the Tags entry. It defaults to contain the word 'all'. I think that that means that all the widgets get the binding? Anyway, I habitually remove the all when associating bindings with widgets.
def method(self, a, b, c = None): print a print b if c != None: print cOne other point, if you need to import a module in order to execute a function, then put the import statement inside of the function. Special Widget Processing: Menu Specification
There is a special menu for creating menu for menu buttons. It can be entered by double clicking on the menubutton. Thus, to create a menu, select a menu button from the tool bar and put it on the window just like any other widget. Then 'go to' the Attribute editor and modify the attributes as desired. From there, you can click on the menu attribute or double click on the widget itself.
Once in the menu window, you can select various types of entries like
command, radio button, check box, or separator. Select add to put them
in the list. If you select command, then it will say something like Put the mouse on that line and Double-Button-1 and yet another window
opens up where you can type the command. You probably want to restrain
your self to a one liner, perhaps a function call.
In Visual Tcl, I have not found a mechanism for specifying a menu-bar.
You can place menu buttons anywhere in the window. I have taken a more
restricted view, creating a menu-bar and putting all of the menu button
inside. This means, for instance, that you cannot put a menu button inside
a page of a tixNotebook.
Menubutton placement is one of the very few places where I use pack,
putting the menubuttons to the left of the menubar with the exception of
a "Help" menubutton which goes to the right. One thing this means is that
you do not have to use a lot of care in placing the menu button in the
PAGE window. When the Python code is generated, the menu buttons are sorted
according to their 'leftness' (in accending order of the x value of the
placement) and accordingly packed into the menu bar. This allows you to
change the order of the menubuttons easily.
The widget as placed will have 2 blank pages in which other widgets
can be placed. Page 1 is on top and widgets can be added. To add other
pages to the note book or to bring up other pages for manipulation select
the note book with Button-3, a pop up menu allows you to add a page or
select one of the existing pages.
I have added many different widgets to a page of a note book, but I
ran into trouble putting a TixNoteBook in a page of a TixNoteBook. I want
to get this out rather than fix up that pathological case.
To use it, one executes the emacs command (server-start) and then goes
in to the File menu of PAGE and selects Preferences and set the Use Emacsclient
checkbox. If you do that, when it comes to Selecting the Generate Python
from the pop up menu, the resulting code will appear almost magically in
an emacs buffer. There it is possible to edit file, execute it, print it,
etc.. When one wants to return to PAGE, just issue again the (server-start)
command.
When you select the top level widget and Generate Python from the popup
menu, the Python Window will appear in all of its grey glory and it will
be filled with the generated code. You can push the run button and execution
will be attempted. This will automatically save the generated code in a
py file where the root name matches the tcl file. Another thing you can
do is save the python module, 'go to' a terminal window, and run the program
there. What I prefer doing is to have emacsclient turned on so that the
generated code will appear in an emacs buffer where I can execute it and
usually I have to debug it.
A disadvantage of using the Python Window is that you are saddled with
the Tix color scheme, whereas if you run it outside of PAGE, it will respect
the settings in TkoptionDB.
When running in Python Window, line output from the GUI is directed
to the lower window of the Python Window.
A final word about running in the Python Window is that the tcl file
will be automatically saved as well as the python file. If no name has
been selected for the project, then a file output window will open and
you will be presented with a way to choose the tcl file name, the root
of which will be used for the python file name. I have not implemented
a 'save all' in the python window. To do that, 'go to' the main PAGE menu
and do a save all, return to the Python Window, and select save or run.
Obviously, you can't load just any python file; but PAGE will take the
function information from a PAGE generated python file and put it into
the corresponding tcl file which can be loaded.
You will see in the File menu the 'Load Python' selection. How can a
Tcl program manipulate Python code?, you ask. Of course, it can't. What
happens is that a program 'inc.py' is invoked which reads the tcl file
and replaces all of the user defined procedures in it with corresponding
functions in the corresponding py file.
I would like to replace 'inc.py' with a program which will take the generated Python program
and generate from it a corresponding tcl module that could be sourced.
That would be good because it would obviate the need to keep the python
and tcl versions of the program in step and would preserver manual changes
to the widget invocation and configuration. The down side is that it would
have to be very stylized and thus might be a bit fragile.
I have now coded such a translator in Python; it is p2t.py and have included
it in the distribution. It is up to you to decide whether you would prefer
to keep the tcl version around or to try the regenerated version. One
invokes p2t with:
The trick to building p2t was to realize that the resulting tcl program did
not have to execute. All it has to do is set up a few data structures when
it is sourced. I would be very surprised if there were not a bunch of
errors in p2t. So, my recommendation is to continue to keep the 'tcl'
companion file around. But if you loose it try p2t, and let me know about
the problems that you face. When I get more confidence in p2t, I will
incorporate it replacing inc. p2t.py is to be found in the main page
installation directory.
The generated code will attempt to load an option file from the python
subdirectory in your home directory. The name of the file is TkoptionDB
and is of the same format as that of '.Xdefaults'. Most Tcl/Tk books discuss
the option database.
I have include my TkoptionDB file in the top level of the PAGE distribution
directory. It contains just two lines:
Again, let me acknowledge that PAGE is built on top of Visual Tcl.
Without that work I probably would not have known how to get started.
Finally, I got a much essential help and very fast response from Ioi
Lam, the author of Tix.
Special Widget Processing: TixNoteBook Specification
One can create a TixNoteBook one on the GUI by (1) selecting the root window,
and (2)selecting the notebook icon on the tool bar. Then drag it to it
its destination on the GUI and resize it by (1) selecting the widget with
Control-Button-1, (2) holding down the buttons while dragging it to its
home, and (3) select it again with Control-Button-1 and drag a handle (one
of those 8 black globs around the edge).
Using emacsclient
As I mentioned above, I use emacs as my preferred IDE and so I set up PAGE
to use emacs for displaying and debugging the generated python code as
well as for writing the functions for the GUI.
Running the Generated Gui
The generated GUI is written in such a way that it will run stand alone
as a script. The final lines of the module are:
if __name__ == '__main__':
vp_start_gui()
which will call vp_start_gui when the the script is exercised. The key
is vp_start_gui which is generated automatically. This is the function
which your application modules should call. I recommend that you do not
modify it. It contains:
def vp_start_gui():
global w
root.title('New_Toplevel_1')
root.geometry('934x975+86+69')
w = New_Toplevel_1 (root)
init()
root.mainloop()
Note that it contains a call to init() which is the routine that you supply
if you need to execute initialization code. I believe that PAGE will supply
the following null init function
def init():
pass
if none is specified. To get some real function you can either define the
init function in PAGE or edit the null init after GUI generation.
Loading Python Files
As mentioned above, as you debug the generated GUI you will likely make
changes to the functions in it and may want to modify the GUI. It is very
important that you do not have to manually reenter information about the
procedures into the tcl file.
python p2t.py python_file_name
Using the Option Data Base.
*font: helvetica 18
*background: wheat
giving me large fonts and a 'wheat' colored background. The entrys follow
the format of the Xdefaults file. I find that the use of an options file
is very convenient and helpful. If you want to change fonts, colors, or
any other attributes, this may be the place to do it.
Final Recommendations
Save often.
Spring for Grayson's book.
Save often.
Acknowledgements
First to HP for assigning the rights of PAGE to me which allows
me to make this available to the Python community.