I am having trouble finding a way to accomplish what I want using buttons in tkinter. I am programming a multi-frame tkinter app, for myself, and each frame is a class, each class has buttons that I place on the screen in the __init__ method. I am having trouble trying to link the buttons and the command functions together.
Example:
class frameHome:
def __init__(self,parent, controller)
self.frame=tk.Frame(parent)
self.buttonOne=tk.Button(self.frame,text="Click Me") # I want to add the command here
self.buttonOne.pack()
def buttonOneClick():
print("You clicked me")
When I add the command in the tk.Button() call it says buttonOneClick not defined. One video I watched said to add the function at the top of the code. I would like to keep the function as a method of the class for organization, as well as keep init at the top of the class and was wondering if there is a way to create a reference to the function so I can have it as a method after the the init method and be able to call it in the init method, because I would like the init method to create the gui and link all widget commands for that class/frame in it.
Thank you for any time and help that you can offer
in your command did you write the command as command=buttonOneClick()? if that's the case then you should replace it with self.buttonOneClick()
The answer I needed was that I forgot the self param in the buttonOneClick(self, msg) method.
Related
I need some help form all of you, so i have something like this
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
...
...
...
def _login_btn_clickked(self):
...
...
result = messagebox.askyesno("Wrong username or password.", "Do you want to try again?")
if result == True:
self.__init__(self)
So if the user select the option to try again i need the whole program start again, and show the login box. But when i execute the program the process fail.
But when i execute the program the process fail.
Actually it should. __init__ method is normally called once an instance is created. You need to redesign this to either recreate an instance (first call pack_forget on that frame and then make new one and pack on that place), or do it using methods, like show_loginbox etc
Usually, loginboxes are made using Toplevel with Entry as fields and some buttons to post a result. If done so, on error you could simply erase login or/and passwords entry box and show an error
What I mean is:
reference implementation of above is here
Are you using tkinter.Frame?
I should think that it wouldn't like being reconstructed through the use of
super().init()
While already being packed into a root window (I'm adsuming that is the setup you have).
Now i understand the concept of instance variables and classes, I've never had a problem with them before and I use them frequently. However when I make my MainWindow class, everything is peachy until i try accessing instance variables.
http://pastebin.com/tDs5EJhi is the full code, but at this point it's just placing labels and frames and whatnot, no actual logic is going on. The window looks fine and nothing bad happens.
My question comes to be when I try changing things inside of the window externally. I figured I could just make an instance of the class and change variables from there (namely instancevariable.ImageCanvas.itemconfig()) like i can normally, but Tkinter isn't being nice about it and I think it's a result of Tkinter's mainloop().
Here's the tidbit of my class MainWindow() that i'm having trouble with (ln 207)
...
self.C4 = Tk.PhotoImage(file="temp.png")
self.card4 = self.CardCanvas.create_image(120,46,image=self.C4, state=Tk.NORMAL)
#self.CardCanvas.itemconfig(4, state=Tk.HIDDEN) # < It works here
...
self.root.mainloop()
window = MainWindow()
window.CardCanvas.itemconfig(4, state=Tk.HIDDEN) # < It doesn't work here
That's how i learned how to edit instance variables. When the window pops up, the itemconfig command doesn't actually apply like it would were it inside the class (or maybe it did and the window just didn't update?) and after closing the window I get this error:
_tkinter.TclError: invalid command name
which I assume is just because it's trying to apply a method to variables that don't exist anymore, now that the window has closed.
So I guess here's my big question - I have a MainWindow class, and from what I can tell, nothing can be changed from outside of the class because the Tk.mainloop() is running and won't stop to let other code after it run, like the itemconfig. How do I go about changing those variables? Code after the instance variable declaration doesn't seem to run until the MainWindow() is closed.
You are correct that code after mainloop doesn't run. It does, but only after the GUI has been destroyed. Tkinter is designed for the call to mainloop be the last (or very nearly last) line of executable code. Once it is called, all other work must be done as reaction to events. That is the essence of GUI programming.
The answer to "how do I go about changing the variables" is simple: do it before you call mainloop, or do it in reaction to an event. For example, do it in a callback to a button, do it in a function bound to an event, or to a time-based event via after, and so on.
I solved the problem I asked for in Put a Label in a function-generated window from another function
Now, I have another problem on the same script.
def window1():
windowone=Tk()
button1=button(windowone, command=window2)
def put():
labeltoput=label(windowtwo, text"text to put")
def window2():
windowtwo=Tk()
putlabel=button(windowtwo, text="put label on windowone", command=put)
Now, when I click on the Button putlabel, I want that the label in the function put goes in the windowtwo, instead of appearing in the windowone.
They're all global variables.
You can't call Tk() twice in the same program1. If you want a window, create an instance of Toplevel.
1Technically you can, but only when you understand the ramifications. Unless you have a fairly deep understanding of Tkinter, it almost certainly won't behave like you expect it to.
When I implements the function that is executed when a button is clicked, the code is like this:
self.connect(btnBrowse, SIGNAL("clicked()"), self.browseFile)
and I implement the function browseFile
def browseFile(self):
But when i am inside the method browseFile, I don't have information about the button being clicked, because I want to implement just one function browseFile for many buttons. how can I do to have more information the slot, for example to have my function looks like this:
def browseFile(self, option):
Thanks
Connect to a lambda (or use functools.partial).
Also note the use of new style syntax, which is much more readable and pythonic.
self.btnBrowse.clicked.connect(lambda: self.browseFile(option))
Sender() provides a pointer to the button that sent the event, you can then read the button text (or other associated data) to determine which button was pressed
This is the basic layout of my program:
class App(CheckInfo):
def __init__(self, master):
CheckInfo.__init__(self)
master.title("Example")
.....
After that I have i method (inside the class App) that goes like this:
def moveIt(self):
print "It doesnt work"
At the bottom (outside if the class) I have:
root = Tk()
app = App(root)
#root.bind("<Up>",) # I don't know how this works
root.mainloop()
I am trying to make a bind to the root so that at any moment in the window I can press the up key an call the method.
I'm not sure how this is done.
My guesses so far have not made much progress.
I think I might need to put event in: moveIt(self) => moveIt(self,event)
But I have no idea how to put the method as an argument in the bind since:
root.bind("<Up>",moveIt) #doesnt work
root.bind("<Up>",self.moveIt) #obviously not
root.bind("<Up>",root.moveIt) #donsnt make much sense
Any ideas would be appreciated! I hope I have posted all the relevant code, otherwise please ask for any needed clarification.
Thanks in advance.
Your experiments may not be working because a frame by default does not have the keyboard focus. Try adding root.focus() so that keyboard events are directed to the root window.
The other part of your question has to do with how to do the binding. Since moveIt is a method of the class App and 'app' is an instance of that class, what you want is:
root.bind("<Up>", app.moveIt)