On Wed, 26 Jul 2006 12:46:39 +0200, H J van Rooyen <mail@microcorp.co.za
wrote:
Quote:
Hi,
>
I am struggling to get the pack method to do what I intend.
I am trying to display user input in a seperate window, along with
a little description of the field, something like this:
>
Current entry
Company : entered co. name
First entry : entered stuff
The second entry: more entered stuff
Entry number three : Last entered stuff
You won't be able to do that kind of layout with pack. This is - quite
obviously IMHO - a job for grid, since your widgets are arranged in a grid.
According to my experience, pack should only be used for *very* simple
layouts, such as all widgets in a single row or in a single column. Trying
to do anything else will very soon end up being a nightmare, with unneeded
frames everywhere. Learn to use grid and life will be far easier for you..
[snip]
A few comments on your code:
Quote:
#!/usr/bin/python
# The original of this module is supposed to do an accounting entry -
>
# we get the gui stuff
>
from Tkinter import *
>
class Entryscreen(Frame):
Why do you inherit from Frame? Apparently, you're trying to do a window.A
Frame is not a window; it's a general-purpose container for widgets. If
you want to do a window, inherit from Tk (for a main window) or from
Toplevel (for any other).
Quote:
"""This screen is used to construct a new Entry."""
>
# we define the variables we use
>
des_string = '' # Description of what we want to do
req_string = '' # Prompt string
dis_string = '' # Description of field for display
>
Company = "New Entry Screen" # we dont have a company yet
Entry_1 = '' # or any entries
Entry_2 = ''
Entry_3 = ''
>
def start_new(self):
"""This is the routine that assembles a new record"""
>
if self.Company == "New Entry Screen": # if its the firsttime,
>
# we make a new window
>
show = Tk()
No, we don't. We actually create a whole new tcl/tk interpreter
environment, completely independent from the one we already have, which
happens to create a new main window. Doing so is bound to cause problems
later. If you want to create a new window, instantiate Toplevel.
Quote:
show.title('Accounting entry display window')
>
# we get an instance to display results in
>
self.disp = Showscreen("Current entry",master=show)
>
# then we ask for the company:
>
des_string = "Getting the Company "
req_string = "Enter the Company for this session"
dis_string = 'Company:'
error = self.GetEntry(des_string, req_string, dis_string,
self.disp)
self.Company = self.Amount
>
# Then or else we ask for entry details
>
des_string = "Getting first entry"
req_string = "Enter first field"
dis_string = "First entry:"
error = self.GetEntry(des_string, req_string, dis_string,
self.disp)
>
des_string = "Getting second entry"
req_string = "Enter second field"
dis_string = "The second entry:"
error = self.GetEntry(des_string, req_string, dis_string,
self.disp)
>
des_string = "Getting third entry"
req_string = "Enter third field"
dis_string = "Entry number three:"
error = self.GetEntry(des_string, req_string, dis_string,
self.disp)
This is not important, but why do you always create variables for your
strings instead of passing them directly? For example, the previous 4
lines can be written:
error = self.GetEntry("Getting third entry", "Enter third field", "Entry
number three:", self.disp)
This would shorten your code a lot. And why do you always pass self.disp
as the last argument? This is an attribute, so using it directly inside
the GetEntry method is not a problem.
Quote:
def GetEntry(self, des_string, req_string, dis_string, disp):
"""Entry routine for one field"""
>
line = Entryline(des_string, req_string, dis_string, disp,
master=root)
error = line.mainloop()
*Never* call mainloop twice in an application! This is not the way to go..
If you want to do a modal dialog, you have to use the wait_window method,
which waits for a given window to be closed.
Quote:
self.Amount = line.retstring
line.destroy()
>
def say_bye(self):
print 'Have a nice day, Bye!'
self.quit()
>
def createWidgets(self):
>
self.descr = Label(self)
self.descr["text"] = self.Company
self.descr["fg"] = 'purple'
self.descr['bg'] = 'yellow'
self.descr.pack({'expand': 'yes', 'fill': 'both', "side": "top"})
This can be written:
self.descr.pack(side=TOP, fill=BOTH, expand=1)
which is shorter and IMHO clearer. TOP and BOTH are constants defined in
the Tkinter module, and passing named arguments is exactly the same as
passing a dictionary.
Quote:
Start = Button(self)
Start["text"] = "Start a new entry"
Start["fg"] = "blue"
Start['bg'] = 'green'
Start["command"] = self.start_new
Again, replace the 5 last lines with:
Start = Button(self, text="Start a new entry", fg='blue', bg='green',
command=self.start_new)
Quote:
Start.pack({'expand': 'yes', 'fill': 'both', "side": "left",
'after':
self.descr})
(see above)
Quote:
QUIT = Button(self)
QUIT["text"] = "QUIT"
QUIT["fg"] = "black"
QUIT['bg'] = 'red'
QUIT["command"] = self.say_bye
QUIT.pack({'expand': 'yes', 'fill': 'both', "side": "left",
'after':
Start})
(see above)
Quote:
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
>
class Showscreen(Frame):
"""This is supposed to show the entries as they occur."""
>
def CreateWidgets(self, Description):
>
self.descr = Label(self)
self.descr["text"] = Description
self.descr["fg"] = 'purple'
self.descr['bg'] = 'yellow'
self.descr.pack({'expand': 'yes', 'fill': 'x', "side": "top",
"anchor":
"n"})
(see above)
Quote:
def __init__(self, Description, master=None):
Frame.__init__(self,master)
self.pack()
self.CreateWidgets(Description)
>
class Entryline(Frame):
"""This asks for an entry from the user and displays the result"""
>
retstring = ''
>
def entryend(self,S):
"""This gets done on carriage return and is where the hassles
originate"""
>
self.retstring = self.estring.get() # get the entered string
You're using retstring both as a class attribute (in "retstring = ''"
above) and here as an instance attribute. This is not really wrong, but a
bit weird. If you want retstring to be a class attribute, you should
access it using Entryline.retstring (and not self.retstring); If you want
it to be an instance attribute, you should remove the line "retstring =
''" above and add a line:
self.retstring = ''
in the constructor below.
Quote:
>
self.disp.Amount_des = Label(self.disp) # and put it into
the
display window
self.disp.Amount_des["text"] = self.dis_string
self.disp.Amount_des["fg"] = 'purple'
self.disp.Amount_des['bg'] = 'yellow'
self.disp.Amount_des.pack({'expand': 'yes', 'fill': 'x', "side":
"left"})
(see above)
Quote:
self.disp.Amount = Label(self.disp)
self.disp.Amount["text"] = self.retstring
self.disp.Amount["fg"] = 'blue'
self.disp.Amount['bg'] = 'green'
self.disp.Amount.pack({'expand': 'yes', 'fill': 'x', "after":
self.disp.Amount_des})
(see above)
Quote:
self.quit() # That's it, folks
>
def createWidgets(self, des_string, req_string):
"""makes the stuff to ask the question"""
>
descr = Label(self)
descr["text"] = des_string
descr["fg"] = 'purple'
descr['bg'] = 'yellow'
descr.pack({'expand': 'yes', 'fill': 'both', "side": "top"})
(see above)
Quote:
req = Label(self)
req ["text"] = req_string
req ["fg"] = 'yellow'
req ['bg'] = 'blue'
req.pack({'expand': 'yes', 'fill': 'both', "side" :"top",'after':
descr})
(see above)
Quote:
self.estring = Entry(self)
self.estring['fg'] = 'black'
self.estring['bg'] = 'white'
self.estring.pack({'expand':'yes','fill': 'both', 'side': 'top',
'after': req})
self.estring.bind('<Key-Return>', self.entryend)
self.estring.focus_set()
>
def __init__(self, des_stringP, req_stringP, dis_stringP, dispP,
master):
>
self.disp = dispP # keep the passed params in instancevars
self.des_string = des_stringP
self.req_string = req_stringP
self.dis_string = dis_stringP
AFAICS, these attributes are never used. Why did you create them?
Quote:
Frame.__init__(self, master)
self.pack()
self.createWidgets(self.des_string, self.req_string)
>
root = Tk()
root.title('Accounting Entry Window')
app = Entryscreen(master=root)
app.mainloop()
root.destroy()
HTH
--
python -c "print ''.join([chr(154 - ord(c)) for c in
'U(17zX(%,5.zmz5(17l8(%,5.Z*(93-965$l7+-'])"