问题描述:

I created a button to call my main_menu function when it is clicked, but it can only be clicked once. When it is clicked, it brings the user back to the main menu, but if the user leaves the main menu and clicks on it again, it does nothing.

def __init__(self):

self.main = main

self.main.grid()

<Really long tuple declared here>

self.main_menu()

def main_menu(self):

self.main.grid_remove()

main = Frame(root)

self.main = main

self.main.grid()

self.sort_button = Tkinter.Button(main, text = "Sort the list using the bubble sort method", command = self.sort_choice)

<Some more buttons coded here>

self.sort_button.pack()

def sort_choice(self):

self.main.grid_remove()

main = Frame(root)

self.main = main

self.main.grid()

<Some other buttons and messages coded here>

self.main_menu.pack()

How can I make a button work more than once?

网友答案:

As stated on the comments, the posted code does not express what is the intended behavior, and probably the whole structure of the code should be changed (and proper naming to be used). I try to clear some concepts, however this answer does not make this code valid (even might not executable).

If you are using global variables (I'm assuming main should be a global variable), when you want to change their values inside a function you need to declare them with global construct. Otherwise changing the value of a global variable in a function would create a local variable with the same name, and won't affect the global variable.

Here is simple code snippet to clear this:

val = "x"                                 

def use_global():                         
    print "Global value is: %s" % val        

def change_global_wrong():                
    print "changing global in change_global_wrong"
    val = "y"                             
    print "global in change_global_wrong is: %s" % val 

def change_global_correct():              
    global val                            
    print "changing global in change_global_correct"
    val = "y"                             
    print "global in change_global_correct is: %s" % val                                                                                                                                                                                                                       

use_global()
change_global_wrong()
use_global()                   
change_global_correct()
use_global()

So changing the value for main inside the functions are actually creating local variable that are going to be out of scope when each function is returned. This means the only reference you have to the main Frame, is self.main. So I suggest register that as the parent for the button.

self.sort_button = Tkinter.Button(self.main, text = "Sort the list using the bubble sort method", command = self.sort_choice)

Even when doing this, by calling the self.main.grid_remove() you are deleting the Frame object. This causes the Frame (and its child widgets) to be removed. Here I've added a code sample for a Tk app (and as specified on the comments, included a way to break it):

#!/usr/bin/env python
import datetime
from Tkinter import *

class MyApp(object):
    def __init__(self):
        self.root = Tk()
        self.time_var = StringVar()
        self.time_var.set('...')
        self._init_widgets()

    def _init_widgets(self):
        self.label = Label(self.root, textvariable=self.time_var)
        frame = Frame(self.root)
        self.frame = frame
        self.button = Button(frame, text = "update time", command = self._on_button_click)
        self.frame.grid()
        self.button.grid()
        self.label.grid()

    def _on_button_click(self):
        self.time_var.set(str(datetime.datetime.now()))
        # uncomment these lines to get a broken code
        #self.frame.grid_remove()
        #self.frame = Frame(self.root)
        #self.frame.grid()

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

if __name__ == '__main__':
    app = MyApp()
    app.run()

Now if you uncomment the bad lines, you would see that calling grid_remove() removes the Frame but creating a new Frame object (and assigning it to same reference) does not help us to recover. Because the old frame that had a nice button on it is gone. And the nice button that would update the time is gone with its parent too.

I'm not sure if the code in this question actually runs or not (since it is missing the context and other lines), but if it runs, I'm expecting that since by clicking on the button, the main frame widget is being removed the button should also be removed from widgets (creating a new Frame should not recover the button).

Since this is not happening (As you say the button is showing but runs no action), I'm concluding the posted lines of code in here are not expressing your situation correctly. Yet I hope these code samples would help you to understand a bit more about your application.

相关阅读:
Top