0

I'm working with tkinter at the moment, ive needed to call a method onto an object that has a Tk() class. im trying to call the method not in the Tk() class, but from the class ive already created, which the tkinter object is in already.

Ive tried to call .Format() onto l_label, but i think it is trying to find an attribute or method within the Label class from tkinter, because it returns: AttributeError: 'Label' object has no attribute 'Format'

Any thoughts?

from tkinter import *
from tkinter import messagebox
from tkinter import filedialog

thing = Tk()

class App():
    def __init__(self, master, _title, back='white'):
        self.master = master
        self._title = _title
        self.back = back
        self.master.title(self._title)
        self.master.configure(background=back)

    def label(self, _text, back='white', w=1, h=1):
        self.back = back
        self.w = w
        self.h = h
        self._text = _text
        l_label = Label(self.master, text=self._text, bg=self.back, width=self.w, height=self.h)
        return l_label

    def Format(self, l_label, Row=1, Column=1):
        self.Row = Row
        self.Column = Column
        l_label.grid(row=Row, column=Column)
        
app = App(thing, 'hello world')
label = app.label('this is a text boc', 'white').Format()
thing.mainloop()
theperson
  • 3
  • 4
  • 1
    pls indent the class – Tkinter Lover Apr 29 '21 at 13:47
  • You have defined `Format` as a method of `App` objects, but it would accept a `Label` as its first parameter. So you'd call it as `app.Format(label)`, or perhaps `app.Format(app.label(...))` if you didn't need the `label` variable for later. – jasonharper Apr 29 '21 at 13:56
  • True, that works. i suppose it was more of to get around to method chaining. Thanks for the answer :) – theperson Apr 29 '21 at 15:16

1 Answers1

0

What you are looking for is method chaining. In order for that to work your function needs to return self

class App(object):
    def __init__(self, master, _title, back='white'):
        self.master = master
        self._title = _title
        self.back = back
        self.master.title(self._title)
        self.master.configure(background=back)
        self.w = None
        self.h = None
        self._text = None
        self.Row = None
        self.Column = None
        self.l_label = None

    def label(self, _text, back='white', w=1, h=1):
        self.back = back
        self.w = w
        self.h = h
        self._text = _text
        self.l_label = Label(self.master, text=_text, bg=back, width=w, height=h)
        return self

    def Format(self, Row=1, Column=1):
        self.Row = Row
        self.Column = Column
        self.l_label.grid(row=Row, column=Column)
        return self

Notice how I removed the l_label from Format and assigned Label(self.master, text=_text, bg=back, width=w, height=h) to self.l_label

Then you would be able to do:

thing = Tk()
app = App(thing, 'hello world')
label = app.label('this is a text box', 'white', 15, 15).Format()
thing.mainloop()
It_is_Chris
  • 13,504
  • 2
  • 23
  • 41
  • Thanks man, that was just what i was looking for :). Is there any reason for all of the self variables to be listed in the __init__ with None value? Or is it to just for the script to be more organised? – theperson Apr 29 '21 at 15:16
  • It is so you do not define an instance attribute outside of `__init__` Here is a quick answer as to why we assign it to None in `__init__`: https://stackoverflow.com/a/19292653/9177877 – It_is_Chris Apr 29 '21 at 17:07
  • Actually `app` and `label` are referring the same instance of `App` class, so `label` is not necessary. – acw1668 Apr 30 '21 at 00:32
  • thats true acw1668, im not sure why i did that – theperson Apr 30 '21 at 01:30