Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I change a variable while inheriting?

I'm using OOP for the first time, I want to make the SubWindow class inherit all properties from the MainWindow class, but self.root would be tk.Toplevel() instead of tk.Tk():

import tkinter as tk

class MainWindow:
    def __init__(self, size, title):
        self.root = tk.Tk()
        self.root.geometry(size)
        self.root.title(title)
        
    def packAll(self):
        for widget in self.root.children:
            self.root.children[widget].pack()
            
class SubWindow(MainWindow):
    def __init__(self, size, title):
        super().__init__(size, title)

If I put self.root = tk.Toplevel() after super().__init__(size, title), it still creates another instance of tkinter. Private variables haven't worked either. I haven't found a solution online. How do I solve this?

like image 889
bfnxjdjd Avatar asked May 16 '26 02:05

bfnxjdjd


2 Answers

What you can do is to pass a required value for self.root to the base class constructor, with a default where the base class chooses tk.Tk():

import tkinter as tk

class MainWindow:
    def __init__(self, size, title, root=None):
        if root == None:
            root = tk.Tk()
        self.root = root
        self.root.geometry(size)
        self.root.title(title)
        
    def packAll(self):
        for widget in self.root.children:
            self.root.children[widget].pack()
            
class SubWindow(MainWindow):
    def __init__(self, size, title):
        super().__init__(size, title, tk.Toplevel())

This way only one root is instantiated, occurring before geometry() and title() are called.

But, really, you shouldn't have to have if statements when you can just pass in the right values:

import tkinter as tk

class Window:
    def __init__(self, root, size, title):
        self.root = root
        self.root.geometry(size)
        self.root.title(title)
        
    def packAll(self):
        for widget in self.root.children:
            self.root.children[widget].pack()
            
class MainWindow(Window):
    def __init__(self, size, title):
        super().__init__(tk.Tk(), size, title)

class SubWindow(Window):
    def __init__(self, size, title):
        super().__init__(tk.Toplevel(), size, title)
like image 66
quamrana Avatar answered May 19 '26 03:05

quamrana


You can use a private class variable:

import tkinter as tk

class MainWindow:
    _root = tk.Tk

    def __init__(self, size, title):
        self.root = type(self)._root()
        self.root.geometry(size)
        self.root.title(title)

    def packAll(self):
        for widget in self.root.children:
            self.root.children[widget].pack()

class SubWindow(MainWindow):
    _root = tk.Toplevel

type(self) accesses the class instead of the instance, otherwise self._root() is treated as a bound method call, with self passed to _root().

like image 24
wjandrea Avatar answered May 19 '26 02:05

wjandrea



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!