0

Hi I am pretty new to tkinter and have being trying to create a button that opens a window then a have a button in the new window the gives a message when pressed. I ran into the problem that the only whay I could get it to recognise the function I wrote was to write it inside the function that opens the second window. I don't know if I have being searching for the wrong things but I can't find how to do this properly. Can someone help me out Here is my code

from tkinter import *
master = Tk()
master.title("frame control")


def win():
    window2 = Toplevel()

    def open():
        stamp = Label(window2, text="Staped").pack()
    lab2 = Button(window2,text = "yo ",command = open).pack()


lab1 = Button(master,text = " open a new window" , command = win).pack()


mainloop()

link
  • 23
  • 5
  • 2
    Make `window2` global so you can access it from any where. Also when you use ` = Button(...).pack()`, `` will always be `None`. For more information about that please read [this](https://stackoverflow.com/questions/1101750/tkinter-attributeerror-nonetype-object-has-no-attribute-attribute-name) – TheLizzard May 14 '21 at 21:16
  • I would say that this is the proper way, there are no issues with this code the only thing You may want to avoid is using `open` since it is already a built-in function but if You don't use as that then it should be fine. – Matiiss May 14 '21 at 21:19
  • @Matiiss Defining functions inside functions isn't a good practise. Also if OP isn't going to use the built in `open` function, it's fine to use it as a variable for a function – TheLizzard May 14 '21 at 21:20
  • Why is it not? Using `global` isn't good practice either and it is possible to avoid that in functional programming too (tho not as easy especially for large programs but at that point only functions shouldn't be used either because it is easier to do with classes (which avoid both of these: using `global` and `nested functions` (mostly at least))) – Matiiss May 14 '21 at 21:23
  • @Matiiss nested functions are worse than global variables. The only problem with global variables is that you need to keep track of which variable names are in use and which are free to be used. With nested functions you can get a lot of problems. Also all variables not defined in a function are global. So are you suggesting that OP should move the `master = Tk()` inside a function? – TheLizzard May 14 '21 at 21:27
  • @TheLizzard well from what I read using `global` can introduce some unexpected side effects to functions which may be hard to debug but at the same time they are not too bad, at the same time nested functions didn't seem to cause any more issues than readability so again they are not too bad either, at the conclusion I would say that both options are pretty valid (tho something was mentioned about that beginners shouldn't use nested functions for some reason but...). About the current code there are no issues tho, it works fine. – Matiiss May 14 '21 at 21:39
  • @Matiiss The only problem with global variables is if you don't keep track of the variables names you used. From OP's question *"I could get it to recognise the function I wrote was to write it inside the function"*, I think OP is trying to remove the nested functions and needs help with that. – TheLizzard May 14 '21 at 21:42
  • @TheLizzard Also I actually just recently learned (I think actually from You) that variables outside functions are global and I am definitely not suggesting moving `root = Tk()` inside a function, I think it is completely fine as is. What I may want to suggest is using classes but that is a bit off-topic for this question. – Matiiss May 14 '21 at 21:42
  • Thanks for the help @TheLizzard. I actually tried making def open but never thought of making the second window global – link May 14 '21 at 21:43
  • Thanks as well @Matiiss – link May 14 '21 at 21:47
  • @Matiiss what situation would make you consider using classes instead? – link May 14 '21 at 21:49
  • 1
    Well if I were to write some project and I expected it to be somewhat large or I wanted to be able to expand on it, I would use classes, although they can be used for smaller projects too, they just help organize the code and can serve as templates which is very useful and one of the main reasons I would consider their use. So the other major use would be to use class as a template even if the project or code is small but I need multiples of sth that in core is the same. – Matiiss May 14 '21 at 21:55

1 Answers1

1

This is your code but with best practises:

import tkinter as tk

def create_stamp():
    stamp = tk.Label(window2, text="Stamp")
    stamp.pack()

def create_second_win():
    global window2
    window2 = tk.Toplevel(root)
    lab2 = tk.Button(window2, text="Click me", command=create_stamp)
    lab2.pack()


root = tk.Tk()
root.title("Frame control")

button = tk.Button(root, text="Open a new window", command=create_second_win)
button.pack()

root.mainloop()

I made window2 a global variable so that I can access it from create_stamp. Generally it is discouraged to use from ... import *. As @Matiiss said, sometimes you can have problems with global variables if you don't keep track of the variable names that you used.

If you want to avoid using global variables and want to use classes, look at this:

import tkinter as tk


class App:
    def __init__(self):
        self.stamps = []

        self.root = tk.Tk()
        self.root.title("Frame control")

        self.button = tk.Button(self.root, text="Open a new window", command=self.create_second_win)
        self.button.pack()

    def create_stamp(self):
        stamp = tk.Label(self.window2, text="Stamp")
        stamp.pack()
        self.stamps.append(stamp)

    def create_second_win(self):
        self.window2 = tk.Toplevel(self.root)
        self.lab2 = tk.Button(self.window2, text="Click me", command=self.create_stamp)
        self.lab2.pack()

    def mainloop(self):
        self.root.mainloop()


if __name__ == "__main__":
    app = App()
    app.mainloop()

As @Matiiss mentioned it would be more organised if you move the second window to its own class. For bigger projects it is a must but in this case you don't have to.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
  • 1
    I would like to add that in the second example in case the windows contain a lot, it would be better to create two separate classes for each window (so that the code is more readable and organized but that is up to whom ever writes the code) – Matiiss May 14 '21 at 22:00
  • @Matiiss You are right that it will make it more organised and I will add that to my answer. But given that there are only 3 variables that will be moved to the new class, I don't think it is worth the time doing that. – TheLizzard May 14 '21 at 22:03
  • @TheLizzard I very much appreciate the time you took to give me an in-depth answer. I think I have a good understanding of what is going on now. With the exception of when you create the class (I have never seen a class like this and don't really fully understand it tbh) – link May 14 '21 at 22:35
  • @link There is nothing special about the class up there. What types of classes have you seen? – TheLizzard May 15 '21 at 08:33
  • @ TheLizzard every time I have ever seen classes used all the variables are defined in def __init__(self,var1,var2,.....) then self.var1 = var1 .... I don't really know what is happening without that – link May 16 '21 at 16:43
  • @link In python you can define variables that belong to the class whenever you want. It isn't like C/C++ where you need to define all of the variables that belong to the class in the constructor. – TheLizzard May 16 '21 at 16:45