Can you change a widget's parent in python tkinter?
Asked Answered
B

2

19

Is there any way to change a widget's (ttk.frame in this case) parent? I can't find any keywords to use in the widgets .config. Is this not possible in python tkinter? What I'd like functionally is to take my current frame in my tkk.notebook widget, and when I double click the tab, to have everything in the frame of the tab, move to it's own separate TopLevel window. This way the user can have a visual reference to that tab while working on another tab. I couldn't think of any other way to have this happen without the frame functionality I'm asking about. Perhaps if anyone can circumvent this issue, I won't need to worry about parent widget capabilities.

Cheers, Chris

Briscoe answered 8/6, 2011 at 21:44 Comment(0)
R
13

An old post by Fredrik Lundh (the Tkinter author) suggests that it isn't possible to change a widget's parent.

Ry answered 10/6, 2011 at 17:12 Comment(1)
Hmm, that's unfortunate. Thanks though.Briscoe
D
0

You cannot move a widget or group of widgets to a new parent but you can simulate that with some simple routines. I don't work in python but you should be able to convert the following code to tkinter from the tcl. By simulate I mean you copy the widget and any chidren recursively to a new parent. Tk provides the introspection needed to exactly copy the layout, bindings, and look of the widget to be moved/copied including all subwidgets. The routines that follow will allow you to move or copy both single or complex widgets to a new parent.

proc getWidgetType { w } {
    set class [winfo class $w ]
    if { [ string index $class 0 ] eq "T" &&
     [ string match "\[A-Z\]" [string index $class 1 ] ] } {
        set class [string range [string tolower $class ] 1 end ]
        set class "ttk::$class"
    } else {
        set class [string tolower $class ]
    }
    return $class
}
proc getConfigOptions { w } {
    set configure [ $w configure ]
    set options {}
    foreach f $configure {
        if { [llength $f ] < 3 } { continue; } 
        set name    [ lindex $f 0 ]
        set default [ lindex $f end-1 ]
        set value   [ lindex $f end ]
        if { $default ne $value } {
            lappend options $name $value 
        }
    }
    return $options
}
proc copyWidget { w  newparent { level 0 } } {
    set type [ getWidgetType $w ]
    set name [ string trimright $newparent.[lindex [split $w "." ] end ] "." ]  
    set retval [ $type $name {*}[ getConfigOptions $w ] ]
    foreach b [ bind $w ] {
        puts "bind $retval $b [subst { [bind $w $b ] } ] " 
        catch { bind $retval $b  [subst { [bind $w $b ] } ] } 
    } 
    if { $level > 0 } {
        if { [ catch { pack info $w } err ] == 0 } {
            array set temp [ pack info $w ]
            array unset temp -in
            catch { pack $name {*}[array get temp ] } 
        } elseif { [ catch { grid info $w } err ] == 0 } {
            array set temp [ grid info $w ]
            array unset temp -in
            catch { grid $name {*}[array get temp ] } 
        }
    }
    incr level 
    if { [ pack slaves $w ] ne "" } { 
        foreach f [ pack slaves $w ] {
            copyWidget $f $name $level
        }
    } else {
        foreach f [winfo children $w ] {
            copyWidget $f $name $level
        }
    }
    return $retval
}
proc moveWidget { w newparent } {
    set retval [ copyWidget $w $newparent ]
    destroy $w
    return $retval
}

# assume we have already created a toplevel with complex layout named
# .input with subframe .input.frame.tframe that we want to transfer to
# a new toplevel .x .  There is a cancel button we want to transfer
# also at .input.frame.bframe.icancel and we will grid it into
# .x.tframe .

toplevel .x
set form [ moveWidget .input.frame.tframe .x ]
set cancel [ moveWidget .input.frame.bframe.icancel .x.tframe ]
grid $cancel -row 2 -column 2 -sticky new 
pack $form -anchor center -expand 1 -fill both -side top
Demineralize answered 31/3, 2019 at 3:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.