0

This is a complicated question based on the solution of cloning widgets from this answer.

Basis:

When cloning widgets using this method any functions that are reliant on the references of those widgets are not transfered to the new widgets. e.g.:

from tkinter import *
from so_clone import clone_widget

def test(event, widget):
    print(widget.get())
def clone(event, widget, root):
    t= Toplevel(root)
    c = clone_widget(widget, t)
    c.pack(side=TOP)

root = Tk()
f = Frame(root)
f.pack(side=TOP, fill=BOTH, expand=1)
e = Entry(f)
e.pack(side=TOP)
Button(f, text="print", command=lambda e=Event(), w=e:test(e, w)).pack(side=BOTTOM)
Button(root, text="clone", command=lambda e=Event(), c=f, r=root:clone(e, c, r)).pack(side=BOTTOM)
root.mainloop()

When cloning the widget using this method the cloned print button is still referencing the original Entry as it is a perfect duplication.

What I am looking to do is reassign the e variable from the original Entry to the cloned Entry. To achieve this I have created 3 new classes for creating the cloned window and holding the paths.

class Tree:
    def __init__(self):
        self.widgets = {}
    def add(self, w)
        self.widgets[str(w)] = w
        return w
    def get(self, path):
        for w, p in self.widgest.items():
            if p == path:
                return w
        return None

class Popout(TopLevel):
    def __init__(self, root, **kwargs):
        self.root = root
        self.tree = kwargs.pop('tree', tree) ## take the input tree or make a new one.
        super(Popout, self).__init__(root) ##creates toplevel window
        self.bind('<Configure>', self._add_widget) ##call when configured = when widget added
    def _add_widget(self, event):
        if event.widget:
            self.tree.add(event.widget)

class Poppable(Canvas):
#    ... Same as Popout just as a canvas that's in the root frame.
    def _popout(self):
        p = Popout(self.root, tree=self.tree)
        c = clone_widgets(self, p) ## here is where i need to recalculate the tree i think
        c.pack(side=TOP)

There are a few additional things that needs to happen for this to work correctly.

  • First the paths must be calculated relative to the base cloned widget.
  • When cloning the paths must be compared to the tree and the widgets be reassigned
  • After cloning all variables associated with the original widgets should be updated to the new widgtets

This is as far as i have gotten with the solution.

The process would be:

  1. create Poppable Canvas
  2. Add Widgets to Poppable Canvas
  3. Widgets are added to Tree which calcualtes their relative path from the Poppable Canvas
  4. Assigne varaible e to Entry inside Poppable Canvas
  5. pop canvas which creates a Popout passing along the tree.
  6. Popout evaluates the tree while cloning the widgets to also get their relative path from Popout and when matching reassigns the widget in the tree
  7. Somehow figure out that e has the Entry assigned and reassign e to the new Entry.

Although this is my current working theory it is not definitive if other methods are possible. I am looking for a solution to the problem as a whole, this example is just the first solution I could reasonable conceive to work.

Scott Paterson
  • 392
  • 2
  • 17
  • What is the `Event` class that you're using, and why are you passing it to the function since the functions don't use it? – Bryan Oakley May 18 '23 at 18:52
  • Event is just `tkinter.Event()`. Its include mainly out of laziness as sometimes lambda passes an automatic event under some situations. by including it as default i dont have to worry if it is or is not included. – Scott Paterson May 22 '23 at 11:06
  • You will _always_ be passed an event when using `bind`, and `never` when using the `command` attribute of a button. – Bryan Oakley May 22 '23 at 16:27
  • Yes but many times i use both command and bind for specific functions. e.g. ctrl+a and menu->select all both using `def _select_all(self, event):`. I know its not explicitly needed however in the method i am trying to achieve with the question it will use both a button and a key combination. This is true for a lot of my project as i am trying to keep to the same design philosophy as windows native applications which can be navigated entirely by the keyboard if required. – Scott Paterson May 23 '23 at 14:35
  • The normal way to do that is to make the event an optional first parameter. That way, you don't have to create a useless instance of `Event`. – Bryan Oakley May 23 '23 at 15:37

0 Answers0