Now I understand where "bloatware" comes from. :)
This will make your eye's water:
###################################
PROG_NAME = "Headache"
from Tkinter import *
PROG_SEARCHMODS = "><=#*~_"
PROGFw = {}
PROGFw["Qty"] = 7
PROGBar = {}
Root = Tk()
ROOTNameVar = StringVar()
ROOTQtyVar = StringVar()
ROOTQtyVar.set("HI")
Clr = {"R":"#FF0000", "D":Button().cget("bg")}
####################
class vEntry(Entry):
def __init__(self, master=None, bar = "", **kw):
Entry.__init__(self, master, **kw)
VCmd = (self.register(self.VCmd), '%s', '%P')
self.configure(vcmd = VCmd, validate='key')
self.MaxLen = self.cget("width")-1
self.icursor(END)
self.VarSet = bar
def VCmd(self, Old, New):
Max = self.MaxLen
if len(New) > 0:
# If the first character of the field's text is one of the search modifiers
# then allow one more character to be entered.
if New[0] in PROG_SEARCHMODS:
Max += 1
if len(New) > Max:
Root.bell()
return False
if self.VarSet != "":
PROGBar[self.VarSet].configure(bg = Clr["R"])
eval("%sBarSVar"%self.VarSet).set(1)
return True
###########################################
def chgPROGChgBar(VarSet, State, e = None):
if State == 1:
# This may be called upon to clear the change bar of a form that doesn't have
# a change bar, so try.
try:
PROGBar[VarSet].configure(bg = Clr["R"])
eval("%sBarSVar"%VarSet).set(1)
except:
pass
elif State == 0:
try:
PROGBar[VarSet].configure(bg = Clr["D"])
eval("%sBarSVar"%VarSet).set(0)
except:
pass
# For some routines to use so they don't have to constantly check to see if
# the change bar state should be changed. The call gets made, but nothing
# happens.
elif State == -1:
return
return
##################################################
def labelEntry(Sub, LabTx, TheVar, Max, Bar = ""):
Label(Sub, text = LabTx).pack(side = LEFT)
if isinstance(Max, basestring) or isinstance(Max, str):
Max = PROGFw[Max]
LEnt = vEntry(Sub, textvariable = TheVar, width = Max+1, bar = Bar)
LEnt.pack(side = LEFT)
return LEnt
######################
def rootDoSomething():
print "Working..."
# Clean all input fields (mostly .strip()'ing)
# Verify what was entered (.upper() and/or look for missing info and/or make
# sure an integer is entrered where only an integer can be entered, etc.)
try:
int(ROOTQtyVar.get())
except:
print "Qty: Must be an integer."
return
# Save to db, or use inputs to make an SQL command for a search, etc.
ROOTNameVar.set("")
ROOTQtyVar.set("")
chgPROGChgBar("ROOT", 0)
print "Done."
return
##################
LFrm = Frame(Root)
ROOTBarSVar = IntVar()
PROGBar["ROOT"] = Frame(LFrm, height = 5)
PROGBar["ROOT"].pack(side = TOP, fill = X, expand = YES, pady = 3)
Sub = Frame(LFrm)
labelEntry(Sub, "Name:", ROOTNameVar, 20)
Sub.pack(side = TOP, pady = 20)
Sub = Frame(LFrm)
labelEntry(Sub, "Qty:", ROOTQtyVar, "Qty", "ROOT")
Sub.pack(side = TOP, padx = 20, pady = 20)
Sub = Frame(LFrm)
Button(Sub, text = "Go", command = rootDoSomething).pack(side = TOP)
Sub.pack(side = TOP)
LFrm.pack(side = TOP)
Root.mainloop()
######################################
It's micro-mini-chunks of code from a 42,000 line inventory and shipping program.
The class does what it needs to do and dovetails in with the rest of the program. So we're telling a View object, the Entry() (you caught me -- trying to learn MVC stuff in iOS/OSX), to control the contents of a Model object, the StringVar(), instead of having model things, functions via .trace(), control the contents of a Model thing, the StringVar(), which would then automagically update the View. Right? Jobs would never approve. He probably wouldn't approve either way.
I might keep it if I can't figure out what happens when you StringVar.trace() on the same variable twice. Using .trace() and just looking at the contents of the StringVar() seems way more straightforward (read non-obfuscated) to me. The only thing that didn't make sense was the lambda. :)
Thanks!
Post by Michael LangeHi,
On Wed, 6 Mar 2013 20:11:39 -0700
Post by Bob GreschkeI saw that earlier in the day (and a couple of weeks ago too). I
understand it just about as well as lambdas. :) Do all of those values
get passed each time a key is pressed?
Yes, when you register a function as validation callback, all the
registered values will be passed each time a validation occurs (which may
be every key press when validate='key', focus in/out events if
validate='focus(in/out)' or all of these if validate='all' .
Post by Bob GreschkeAlso, each Entry() field has a
different max length. Where do I pass that in all of this? It would
need to be an arg to vcmd in the Entry().
This sounds like a job for a custom entry class. I wrote a
quick example to illustrate the usage of the Entry's vcmd that might be a
#######################################################################
from Tkinter import *
Entry.__init__(self, master, **kw)
self._maxlength = maxlength
self.insert('end', value)
vcmd = (self.register(self._vcmd), '%s', '%P')
self.configure(vcmd=vcmd, validate='all')
print old, new
return False
return True
root = Tk()
e = VEntry(root, maxlength=7, value='bar')
e.pack(padx=100, pady=100)
e.focus_set()
root.mainloop()
#######################################################################
You see, the `%s' ("old value") parameter in this example is not really
needed, I added it just to illustrate how to pass multiple arguments to
the vcmd. See http://www.tcl.tk/man/tcl8.4/TkCmd/entry.htm#M16 for a list
of all possible percent substitutions and their meanings.
You could also try if validate='key' is sufficient for your needs.
The one thing one has to be very careful to keep in mind when writing a
validation command callback is that it must always return a boolean value
in any case, otherwise Tk will be "confused" and simply and silently turn
off validation altogether. This may especially easily happen when the vcmd
callback happens to throw an error, so one has to take care that all
possible exceptions are properly caught by try...except statements.