import sys, os
from string import replace
from Tkinter import *
from Tkinter import _cnfmerge,TclError
import tkMessageBox, tkFileDialog, tkSimpleDialog, tkFont
from p_ggen import floate,isString,thanUnunicode
#############################################################################
#############################################################################
class ThanStatusBar(Frame):
"Implements a status bar."
def __init__(self, master):
"Initialise base classes and create status bar (as a label)."
Frame.__init__(self, master)
self.label = Label(self, bd=1, relief=SUNKEN, anchor=W, width=60)
self.label.grid(sticky="swne")
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
def set(self, format, *args):
"Prints formatted text to statusbar."
self.label.config(text=format % args)
self.label.update_idletasks()
def sett(self, text1):
"Prints text to statusbar."
self.label.config(text=text1)
self.label.update_idletasks()
def clear(self):
"Clears the status bar."
self.label.config(text="")
self.label.update_idletasks()
def destroy(self):
"Deletes circular references."
del self.label
Frame.destroy(self)
#############################################################################
#############################################################################
class ThanScrolledTextxxx(Text):
"""Modified standard ScrolledText provided py python distribution.
A horizontal scrollbar is implemented.
Keywords vbar,hbar control the placement of vertical and horizontal bars.
Default vbar=1, hbar=0.
It uses the grid geometry manager.
It changes the colour of the vertical scroll bar.
Function apply was converted to a more readable form.
"""
def __init__(self, master=None, cnf=None, **kw):
drawHbar = kw.setdefault("hbar", 0)
drawVbar = kw.setdefault("vbar", 1)
del kw["vbar"]; del kw["hbar"]
if cnf is None: cnf = {}
if kw: cnf = _cnfmerge((cnf, kw))
fcnf = {}
for k in cnf.keys():
if type(k) == ClassType or k == 'name':
fcnf[k] = cnf[k]
del cnf[k]
self.frame = Frame(master, **fcnf)
self.vbar = self.hbar = None
if drawVbar:
self.vbar = Scrollbar(self.frame, name='vbar')
# Change the color of inactive indicator to the color of active indicator
# because it was confusing to change color when you pressed the button
self.vbar.config(background=self.vbar["activebackground"])
self.vbar.grid(row=0, column=1, sticky="sn")
if drawHbar:
self.hbar = Scrollbar(self.frame, name='hbar', orient=HORIZONTAL)
self.hbar.config(background=self.hbar["activebackground"])
self.hbar.grid(row=1, column=0, sticky="we")
cnf['name'] = 'text'
Text.__init__(self, self.frame, **cnf)
self.grid(row=0, column=0, sticky="wesn")
if drawVbar:
self['yscrollcommand'] = self.vbar.set
self.vbar['command'] = self.yview
if drawHbar:
self['xscrollcommand'] = self.hbar.set
self.hbar['command'] = self.xview
# Copy geometry methods of self.frame -- hack!
methods = Pack.__dict__.keys()
methods = methods + Grid.__dict__.keys()
methods = methods + Place.__dict__.keys()
for m in methods:
if m[0] != '_' and m != 'config' and m != 'configure':
setattr(self, m, getattr(self.frame, m))
self.frame.rowconfigure(0, weight=1)
if drawVbar: self.frame.columnconfigure(0, weight=1)
if drawHbar: self.frame.rowconfigure(1, weight=1)
def destroy(self):
"Delete/destroy any variables we created and saved a reference."
del self.vbar, self.hbar, self.frame
Text.destroy(self)
#############################################################################
#############################################################################
#MODULE LEVEL FUNCTIONS
#============================================================================
def thanTkGuiCreateMenus(self, mlist):
"""Create the menus described in list mlist=thanGetMenus().
mlist is a list of tuples m with 3 values:
m[0] = function to call when menu is activated
m[1] = name of the menu
m[2] = description of the menu
m[3] = foreground color
m[4] = name of Tk object (if == 'help' then it is render at far right)
If m[0] == None and m[1] == '-' then this is a separator
If m[0] == None and m[1] <> '-' then a new menu with name
m[1] is to be created.
"""
#---At first do some initialisation
# self.CreateStatusBar()
menuBar = Menu(self, activebackground="green")
#---Process mlist
menu = None
for m in mlist:
#-------Normal Menu entry
if len(m) > 3: fg = m[3]
else : fg = None
if m[0] != None:
menu.add_command(label=replace(m[1], "&", ""), foreground=fg,
command=m[0]) # Create menu entry
#-------Separator entry
elif m[1] == "-":
menu.add_separator()
#-----------New menu: at first add old menu in menubar
else:
if menu != None: menuBar.add_cascade(label=menuDesc, menu=menu)
menu = Menu(menuBar, activebackground="green", foreground=fg, tearoff=0)
menuDesc = replace(m[1], "&", "")
if menu != None: menuBar.add_cascade(label=menuDesc, menu=menu)
self.config(menu=menuBar)
def thanTkCreateThanMenus(self, mlist, statcommand=None, condition=None):
"""Create the menus described in list mlist=thanGetMenus().
mlist is a list of tuples m with 3 values:
m[0] = function to call when menu is activated
m[1] = name of the menu
m[2] = description of the menu
m[3] = foreground color
m[4] = Tk name: if name=="help" then it is rendered at far right
If m[0] == None and m[1] == '-' then this is a separator
If m[0] == None and m[1] <> '-' then a new menu with name
m[1] is to be created.
"""
from p_gtkwid import ThanMenu
menuBar = ThanMenu(self, activebackground="green", statcommand=statcommand, condition=condition)
submenus = {}
menu = None
for m in mlist:
if len(m) > 3: fg = m[3]
else : fg = None
if m[0] != None: # Normal Menu entry
menu.add_command(label=m[1].replace("&", ""), command=m[0], help=m[2], foreground=fg) # Create menu entry
elif m[1] == "-": # Separator entry
menu.add_separator()
else: # New menu: at first add old menu in menubar
if menu != None:
menuBar.add_cascade(label=menuDesc, menu=menu, help=menuHelp, foreground=fg)
menuDesc = m[1].replace("&", "")
menuHelp = m[2]
if len(m) > 4: name = m[4]
else : name = None
menu = ThanMenu(menuBar, name=name, activebackground="green", tearoff=0, statcommand=statcommand, condition=condition)
submenus[menuDesc] = menu
if menu != None:
menuBar.add_cascade(label=menuDesc, menu=menu, help=menuHelp)
self.config(menu=menuBar)
return menuBar, submenus
#============================================================================
def thanGudGetReadFile(self, ext, tit, initialfile="", initialdir=""):
"Gets a filename that exists, from user."
ext = thanExtExpand(ext)
while True:
opendialog = tkFileDialog.Open(parent=self, initialfile=initialfile,
# initialdir=initialdir, defaultextension=ext[0][1][1:], # For Windows?
initialdir=initialdir, defaultextension=ext[0][1],
title=tit, filetypes=ext)
try:
filnam = opendialog.show()
except TclError, why:
w = str(why)
if "invalid" in w:
if "filename" in w:
initialfile = ""
continue
raise
break
return thanAbsrelPath(filnam)
#============================================================================
def thanAbsrelPath(f):
"Returns the absolute path of f, or, if f is in current dir, the relative path to f."
if not f: return None
f = thanUnunicode(f)
d = os.getcwd()
f = thanUnunicode(os.path.abspath(f))
if os.path.commonprefix((d, f)) == d: f = f[len(d)+1:]
return f
#============================================================================
def thanExtExpand(ext):
"""Extension ext can be one of the following:
string: string is the extension and it is transformed to:
[ (<NULL explanation>, string),
("All files", "*"),
]
tuple of strings: The first string of the tuple is the explanation and the other
string is the extension. It is transformed to:
[ tuple,
("All files", "*"),
]
list of tuples: Each tuple is a tuple of strings. The first string of the tuple is
the explanation and the other string is the extension. No transformation.
"""
if isString(ext): return [("", ext), ("All files", "*")]
if isString(ext[0]): return [ext, ("All files", "*")]
return ext
def thanGudGetSaveFile(self, ext, tit, initialfile="", initialdir=""):
"Gets a filename that may exists, from user."
ext = thanExtExpand(ext)
while True:
opendialog = tkFileDialog.SaveAs(parent=self, initialfile=initialfile,
# initialdir=initialdir, defaultextension=ext[0][1][1:], # For Windows?
initialdir=initialdir, defaultextension=ext[0][1],
title=tit, filetypes=ext)
try:
filnam = opendialog.show()
except TclError, why:
w = str(why)
if "invalid" in w:
if "filename" in w:
initialfile = ""
continue
raise
break
return thanAbsrelPath(filnam)
def thanGudOpenReadFile(self, ext, tit, mode="r", initialfile="", initialdir=""):
"Gets a filename that exists, from user."
while 1:
filnam = thanGudGetReadFile(self, ext, tit, initialfile, initialdir)
if not filnam: return filnam, filnam
try: fw = file(filnam, mode)
except IOError, why: thanGudModalMessage(self, why, "Error opening file")
else: return filnam, fw
def thanGudOpenSaveFile(self, ext, tit, mode="w", initialfile="", initialdir=""):
"Gets a filename that exists, from user."
while 1:
filnam = thanGudGetSaveFile(self, ext, tit, initialfile, initialdir)
if not filnam: return filnam, filnam
try: fw = file(filnam, mode)
except IOError, why: thanGudModalMessage(self, why, "Error opening file")
else: return filnam, fw
def thanGudGetDir(self, tit, initialdir=""):
"Gets a filename that exists, from user."
opendialog = tkFileDialog.Directory(parent=self,
title=tit, initialdir=initialdir)
filnam = opendialog.show()
return thanAbsrelPath(filnam)
#============================================================================
def thanGudAskOkCancel(self, message, title, default="cancel"):
"Shows message and returns true if user pressed OK; there is no default answer."
return tkMessageBox.askokcancel(title, message, default=default, parent=self)
def thanGudAskYesNo(self, message, title, default="yes"):
"Shows message and returns true if user pressed OK; there is no default answer."
return tkMessageBox.askyesno(title, message, default=default, parent=self)
def thanGudModalMessage(self, message, title, icon=None, **kw):
"Show a message and wait until user discards it."
tkMessageBox.showinfo(title, message, parent=self, icon=icon, **kw)
#===========================================================================
def thanGudHelpWin(parentwin, mes, title, hbar=0, vbar=1, width=80, height=25,
font=None, background="lightyellow", foreground="black"):
"Implements an Information window."
import p_gtkwid
help = Toplevel(parentwin)
help.title(title)
font1 = font
if font is None:
import p_gtkuti
font1=tkFont.Font(family="Liberation Mono", size=12)
p_gtkuti.thanFontRefSave(help, font1)
txtHelp = p_gtkwid.ThanScrolledText(help, hbar=hbar, vbar=vbar, font=font1,
background=background, foreground=foreground, width=width, height=height)
txtHelp.thanSet(mes)
txtHelp.grid(sticky="wesn")
help.rowconfigure(0, weight=1)
help.columnconfigure(0, weight=1)
keysallowed = {"Up":0,"Down":0,"Left":0,"Right":0,"Prior":0,"Next":0,"Home":0,"End":0}
def __format(evt):
if evt.keysym not in keysallowed: return "break"
txtHelp.bindte("<Key>", __format)
txtHelp.focus_set()
return help
def thanGudGetText(self, mes, textDefault):
"Accepts a nonblank text via a modal window."
self.update() # Experience showed that there should be no pending
# Tk jobs when we show a modal window
while 1:
ans = tkSimpleDialog.askstring("Please enter text", mes,
initialvalue=textDefault, parent=self)
if ans == None: return ans
if ans != "": return ans
self.bell()
def thanGudGetFloat(self, mes, textDefault):
"Accepts a real number via a modal window."
self.update() # Experience showed that there should be no pending
# Tk jobs when we show a modal window
ans = tkSimpleDialog.askfloat("Please enter a number", mes,
initialvalue=textDefault, parent=self)
return ans
def thanGudGetPosFloat(self, mes, textDefault):
"Accepts a positive real number via a modal window."
ans = tkSimpleDialog.askfloat("Please enter a positive number", mes,
initialvalue=textDefault, minvalue=0.00000001, parent=self)
return ans
#===========================================================================
def thanValidateDouble(parentwin, controls, except_=()):
"""Validates the real values of specified (Entry) controls.
controls is a sequence of the following format:
Description control min value max value
( ("Manning coefficient", self.thanTxtMan, 0.0000001, 0.1),
("slope", self.thanTxtSlo, 0, 1000),
("discharge", self.thanTxtDis, 0, 100000),
("Hydraulic depth", self.thanTxtDep, 0, 1000)
)
except_ is a sequence of controls which should be not validated.
"""
res = []
for c in controls:
desc, control, vmin, vmax = c[:4]
if control in except_: res.append(None); continue
v = floate(control.get())
if v == None or v < vmin or v > vmax:
thanGudModalMessage(parentwin, "Illegal "+desc, "Bad data")
control.focus_set()
return
res.append(v)
return res
#############################################################################
#############################################################################
#MODULE LEVEL CODE. IT IS EXECUTED ONLY ONCE
if __name__ == "__main__":
root = Tk()
# t = ThanScrolledText(root)
# t.grid()
# t = "Thanasis\nDimitra\nAndreas\n=love\n"*20
# thanGudHelpWin(root, t, "well...")
t = thanGudGetDir(root, "get dir", "/tmp")
print t
root.mainloop()
|