Lambda returning tuple question, multi-expression

aapost aapost at idontexist.club
Thu Mar 9 17:16:15 EST 2023


On 3/9/23 04:06, Alan Gauld wrote:
> 

Thank you for the feedback, I appreciate the comments.

To add a little extra, there is actually a reason I lean toward overuse 
of .config() for a lot of things even though they could be sent to the 
constructor (other than that w["attribute"]= doesn't work in a lambda).

It comes from a use case I needed to solve in the shortcoming of tk with 
frames not being scrollable, requiring a canvas.

When dynamically generating a series of widgets (i.e. loading a custom 
json/xml layout config file), getting the scrollable area right is a bit 
of a chore with a catch-22 situation.

With an inner frame in a canvas, pack_propogate(tk.True) is the default 
on the frame, so that the children dictate the size, but in doing so it 
prevents the frame from expanding to the full width of the area it's 
given within the UI layout.

If you turn pack_propogate to tk.False, it breaks the ability for the 
canvas to return bbox(tk.ALL) (which is kind of rough anyway as the tcl 
docs state "The return value may overestimate the actual bounding box by 
a few pixels."). So you end up with 1,1 and no way of knowing what size 
scrollable area to set. Trying to obtain this value from a source 
outside of the canvas requires knowing what you are placing the canvas 
in each time, and was creating a similar catch-22 as the outer widget 
doesn't know what it wants it's size to be without knowing what the 
inner widget wants.. Switching to False, grabbing bbox, then back to 
True of course causes an unsightly flicker and disrupts the smoothness 
of the user experience.

So my solution is to create a widget instantiator which does a few 
things, mainly adding something I call a "ghost".

it's something like this:

instantiator(qlass, master, config_args=None, pack_args=None, 
init_args=None, ghost=False):
   if not init_args:
     init_args = {}
   object = qlass(master=master, **init_args)
   if hasattr(master, "ghost"):
     object.ghost = qlass(master=master.ghost, **init_args)
   elif ghost:
     object.ghost = qlass(master=tk.Frame(), **init_args)

When i pass it a canvas and say ghost=True, the canvas gets a .ghost 
duplicate, which is attached to an arbitrary frame that I never pack and 
stays invisible.

Subsequent widgets created to the canvas then see that their parent, 
starting with the canvas, have a ghost, and in return get a ghost of 
themselves attached to their parents ghost.

This allows you to get an accurate bbox size from the unseen ghost 
canvas that mirrors the visible version.

Keeping the init_args down to only what is necessary helps in 
consistency, and the subsequent config_args and pack_args I have in 
their respective dicts.

This also allows me to create a quality of life pack function I call ppack()

def ppack(self):
   self.pack(**self.pack_args)
   if hasattr(self, "ghost"):
     self.ghost.pack(**self.ghost.pack_args)
   return self

That allows each primary widget to manage and track their own set of 
configurations.

Of course I could strip a lot of that crap out if I find a better and 
smooth way of obtaining those bbox numbers, but I didn't see any quick 
solutions in glancing through the tcl/tk source so I went with what 
works for now.









More information about the Python-list mailing list