简体   繁体   中英

Tkinter destroy method crashes the program

I am trying to make a kind of GUI with tkinter, and here is the code. But, when I run it, click settings, and then back, python crashes. Do you have any idea why this might happen and how I would fix it? It happens when either I run the destroy function, or when I do something in the other Tk window,

The code: (some might not be necessary, but I will include it)

import tkinter as tk

class moveFrame():
    def move(self, event):
        widget = event.widget
        widget.place(x = widget.winfo_x() + event.x - widget.startX, y = widget.winfo_y() + event.y - widget.startY)

def resize(self, event):
    widget = event.widget
    wlength = widget["length"]
    wwidth = widget["width"]
    widget.config(length = wlength + event.x - widget.startX, width = wwidth + event.y - widget.startY)

def getPos(self, event):
    widget = event.widget
    widget.lift()
    widget.startX, widget.startY = event.x, event.y

def __init__(self, master, frameInfo, xPos, yPos):
    self.frame = tk.Frame(master, cnf = frameInfo)
    self.frame.bind("<Button-1>", self.getPos)
    self.frame.bind("<B1-Motion>", self.move)
    self.frame.bind("<B3-Motion>", self.getPos)
    self.frame.bind("<Button-3>", self.resize)
    self.frame.place(x = xPos, y = yPos)


def homescreen():
    screen = tk.Tk()
    #arrangeButton = tk.Canvas(screen, width = 120, height = 40, bg = "purple")
    #arrangeButton.create_text(60, 20, text = "Arrange Homescreen")
    #arrangeButton.place(x = 0, y = 0)
    #arrangeButton.bind("<Button-1>", lambda event: arrange(arrangeButton))
    settingsButton = tk.Canvas(screen, width = 60, height = 60)
    settingsButton.place(x = 20, y = 20)
    settingsButton.create_oval(5, 5, 58, 58, fill = "#a6a6a6", tags = "click")
    settingsButton.create_oval(15, 10, 58, 53, fill = "#000", tags = "click")
    settingsButton.create_oval(27, 22, 46, 41, fill = "#00f", tags = "click")
    settingsButton.tag_bind("click", "<Button-1>", lambda event: settings())

def settings():
    sscreen = tk.Tk()
    #Get previous settings
    try:
        file = open("settings.txt", "r")
    except IOError:
        file = open("settings.txt", "x")
    finally:
        file = open("settings.txt", "r+")
    curSet = [x.strip("\n") for x in file.readlines()]
    #Widgets
    back = tk.Canvas(sscreen, width = 60, height = 48)
    back.place(x = 20, y = 20)
    back.create_rectangle(25, 22, 60, 26, fill = "#000", tags = "sclick")
    back.create_polygon(10, 24, 25, 10, 25, 38, fill = "#000", tags = "sclick")
    back.create_text(42, 32, text = "Back", tags = "sclick")
    back.tag_bind("sclick", "<Button-1>", lambda event: sscreen.destroy())

def arrange(*widgets):
    arrangeScreen = tk.Tk()
    arrangeButton = widgets[0]
    aBaF = moveFrame(arrangeScreen, {"bd" : 4, "bg" : "#a6a6a6"}, arrangeButton.winfo_x() - 4, arrangeButton.winfo_y() - 4)
    aBa = tk.Canvas(aBaF, width = 120, height = 40, bg = "purple")


def load(goTo, ms):
    load = tk.Tk()
    loadImage = tk.Canvas(load, height = 300, width = 300, bg = "black")
    loadImage.pack()
    loadImage.create_oval(125, 130, 175, 180, fill = "white")
    loadImage.create_oval(130, 140, 170, 150, fill = "black")
    loadImage.create_oval(130, 140, 171, 151, fill = "white")
    loadImage.create_oval(152, 140, 148, 150, fill = "black")
    load.after(ms, lambda: [goTo(), load.destroy()])

load(homescreen, 1)

If your program represents one application, only make one Tk instance.

The Tk object represents the root of the entire application, by deleting it and creating another one you are essentially creating a separate application and any references to the previously application results in undefined behaviour such as crashing python.

Instead of using Tk as separate windows use Toplevel as that is what they are intended for, separate windows.

By replacing all occurences of tk.Tk() in your program with tk.Toplevel(abs_root) then defining abs_root as tk.Tk() like this:

abs_root = tk.Tk()
abs_root.withdraw() #hides the window while your program runs.
load(homescreen, 1)
abs_root.mainloop()

Will make your program work, however it does mean that it will run until abs_root is destroyed which cannot happen by clicking the close button since it is not shown as a window, you will either have to use some condition where you explicitly call abs_root.destroy() or choose one window that will be the first created and last to be closed and use that as the abs_root instead. (not possible with your program as it is written)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM