-1

I've searched and read, but don't quite understand other posts and/or it doesn't reflect problem I have.

I've tried different things from similar posts, like this one: Passing variables, creating instances, self, The mechanics and usage of classes: need explanation, but apparantly, I don't understand classes, self quite enough (as can be seen I'm absolute beginner)

from tkinter import Tk, ttk, Frame, Label, StringVar, OptionMenu, Entry, Button, Toplevel
import pymysql as mdb
from functools import partial
from PIL import Image, ImageTk

class Home(object):
    def __init__(self, master):
        self.master = master
        self.master.title("Control Panel")
        self.master.configure(background="#%02x%02x%02x" % (61, 72, 73))
        self.master.geometry("475x190")
        self.master.resizable(width=False, height=False)
        self.main_frame = Frame(master, background="#%02x%02x%02x" % (61, 72, 73))
        self.main_frame.grid(row=1, column=1, columnspan=4, padx=15, pady=15)
        load1 = Image.open('plan.jpg')
        render1 = ImageTk.PhotoImage(load1)
        self.button_plan = Button(self.main_frame, image=render1, command=self.b_clicked('Planning'))
        self.button_plan.image = render1
        self.button_plan.grid(row=1, column=1, padx=12)
        self.label_plan = Label(self.main_frame, text='Planning', font='Calibri 9',
                            background="#%02x%02x%02x" % (61, 72, 73),
                            foreground="#%02x%02x%02x" % (255, 201, 14))
        self.label_plan.grid(row=2, column=1, padx=12)
        load2 = Image.open('consumption.jpg')
        render2 = ImageTk.PhotoImage(load2)
        self.button_consumption = Button(self.main_frame, image=render2, command=self.b_clicked('Consumption'))
        self.button_consumption.image = render2
        self.button_consumption.grid(row=1, column=2, padx=12)
        self.label_consumption = Label(self.main_frame, text='Consumption', font='Calibri 9',
                                   background="#%02x%02x%02x" % (61, 72, 73),
                                   foreground="#%02x%02x%02x" % (255, 201, 14))
        self.label_consumption.grid(row=2, column=2, padx=12)


    def b_clicked(self, id):
        self.button_id = id
        self.master.withdraw()
        self.second_w = Toplevel(self.master)
        self.app = Second(self.second_w, self.button_id)


class Second(object):
    def __init__(self, master, arg1):
        self.master = master
        self.master.title("Second")
        self.master.configure(background="#%02x%02x%02x" % (61, 72, 73))
        self.master.geometry("190x165")
        self.master.resizable(width=False, height=False)
        print(arg1)

root = Tk()
GUI = Home(root)
root.mainloop()

I would like to pass a variable value into another class. In this case I would like to get self.button_id value 'Planning' from class Home to be passed to class Second. Point is... I don't need just solution. I would really like to understand it and this would be a great opportunity to learn it on my own example!

Mr K
  • 111
  • 13
  • Hey Ivan. Can you give us some more information about what this code is being used for? is 'master' inherited from a 3rd party module? Just trying to understand your project from a top level. – Matthew Wachter Sep 06 '19 at 16:24
  • [minimal-reproducible-example](https://stackoverflow.com/help/minimal-reproducible-example) – tgikal Sep 06 '19 at 16:25
  • @Goyo. Sorry, typing mistake – Mr K Sep 06 '19 at 16:28
  • @Mathew, yes master is 3rd party. – Mr K Sep 06 '19 at 16:29
  • Sorry, code is quite big, Ive paste just troubling part. And typing from phone as baby is awake so need to hold her – Mr K Sep 06 '19 at 16:33
  • How is that you know how to pass `self.second_w ` but not `id `? It is the same. – Stop harming Monica Sep 06 '19 at 16:37
  • @Goyo, as said, I'm absolute beginnee. I learn along the way as Im trying to make app and help myself and ease steps I have on my job (which is not IT related). I learned (and stll make mistakes) to pass and return values between functions but still not fully clear between classes – Mr K Sep 06 '19 at 16:44
  • 1
    I dont quite understand – Mr K Sep 06 '19 at 16:52
  • 1
    How does that make a difference between passing `self.second_w `and passing `id`or `self.button_id `? – Stop harming Monica Sep 06 '19 at 17:10
  • Well that's a thing. If I would fully understand I would probably know how to do it. – Mr K Sep 06 '19 at 18:54
  • 1
    Just pretend that `Second` is not a class but a function. "I would like to get `self.button_id` value `'Planning'` from class `Home` to be passed to function `Second`. You know how to do that, don't you? – Stop harming Monica Sep 06 '19 at 21:26
  • I've tried something similar, but now with more success. Yes, it passed a value but instead of opening one "Second" window, it is opening 10 in same time. One for each function call and I expected function to be called upon button click.I forgot to mention (I didn't paste whole code). There is 10 buttons. Each with different value to pass to class Second! I modified code above to this new update! – Mr K Sep 06 '19 at 21:51
  • 1
    Guess what `self.b_clicked('Planning') ` does. – Stop harming Monica Sep 06 '19 at 22:26
  • :) I know that. Initial function was just b_clicked and it opened Second always on button click. But I needed information passed to next window Second about which button is pressed. They all should open Second but from there I should know which button led there. Now Home window is not even opened. It immediately execute b_clicked and not just once but for every button without even clicking on it – Mr K Sep 06 '19 at 22:29

1 Answers1

1

A couple of things:

I reduced your code to get rid of all the code which is not problematic.

When you create the buttons, the command argument runs the callback function instead of just assigning it.

command=self.b_clicked('Planning')   # Will run self.b_clicked

Instead you can use a lambda expression in this assignment:

command=lambda:self.b_clicked('Planning')

In short: the function name is self.b_clicked and normally you would assign command=self.b_clicked, but as you want to pass an argument you will have to use lambda or partial, because ending a function name with parenthesis will just run the function.

As you create two buttons, your program immediately creates two new toplevel windows. When you reuse the name self.second_w for the second window you also lose the reference to the first toplevel window.

Also, you are using the name id for a variable which is not good as id is a builtin function.

Otherwise it seems to work just fine:

from tkinter import *

class Home():
    def __init__(self, master):
        self.master = master
        self.main_frame = Frame(master, bg='tan')
        self.main_frame.pack()

        self.button_plan = Button(self.main_frame, text='Plan', 
                                  command=lambda:self.b_clicked('Planning'))
        self.button_plan.grid(row=1, column=1, padx=12)

    def b_clicked(self, idty):      # "id" is a builtin function
        self.button_id = idty
        self.master.withdraw()
        self.second_w = Toplevel(self.master)
        self.app = Second(self.second_w, self.button_id)

class Second():
    def __init__(self, master, arg1):
        self.master = master
        self.master.configure(bg='tomato')
        print(arg1)

root = Tk()
GUI = Home(root)
root.mainloop()
figbeam
  • 7,001
  • 2
  • 12
  • 18