I am trying to create frame with 2 input areas (for login and password) and confirmation button (after this button is pressed - code will read areas values). But I don't know how to do it inside class App without using some global function.
from Tkinter import *
class App:
def __init__(self, master):
frame_credentials = Frame(master, width=100, height=200)
frame_credentials.pack()
self.label_login = Label(frame_credentials, text='login')
self.text_login = Entry(frame_credentials, width=15)
self.label_pass = Label(frame_credentials, text='password')
self.text_pass = Entry(frame_credentials, show="*", width=15)
self.button_ok = Button(frame_credentials, text="Login")
self.label_login.grid(row=0, column=0)
self.text_login.grid(row=1, column=0)
self.label_pass.grid(row=2, column=0)
self.text_pass.grid(row=3, column=0)
self.button_ok.grid(row=0, column=1, rowspan=4)
self.button_ok.bind("<Button-1>", enter_in)
def enter_in(self):
print self.text_login, self.text_pass
root = Tk()
app = App(root)
root.mainloop()
Don't bind to <Button-1>; instead, use the command attribute and give it the name of a method in your object. For example:
class App:
def __init__(...):
...
self.button_ok = Button(..., command=self.enter_in)
...
def enter_in(self):
<put your login logic here>
Related
I'm currently using tkinter to create a GUI for my program. If I open the golf quiz window and open the help window, then close the golf quiz window and re-open it, I am able to click the help window button and open another instance of the help button. How do I set the Help button to be disabled while the Help window is open?
from tkinter import *
from functools import partial
class Welcome_Screen:
def __init__(self, parent):
self.welcome_screen_frame = Frame(width=200, height=200, pady=10)
self.welcome_screen_frame.grid()
self.quiz_welcome_screen_label = Label(self.welcome_screen_frame, text = "quiz game", font="Arial 20 bold", padx=10)
self.quiz_welcome_screen_label.grid(row=0)
self.welcome_screen_buttons_frame = Frame(self.welcome_screen_frame)
self.welcome_screen_buttons_frame.grid(row=2)
self.golf_quiz_welcome_screen_button = Button(self.welcome_screen_buttons_frame, text="Golf Quiz", font="Arial 10 bold", command=self.golf_quiz_game, padx=10, pady=10)
self.golf_quiz_welcome_screen_button.grid(row=2, column=0, padx=5)
def golf_quiz_game(self):
get_golf_quiz_game = golf_quiz_game(self)
class golf_quiz_game:
def __init__(self, partner):
partner.golf_quiz_welcome_screen_button.config(DISABLED)
self.golf_quiz_box = Toplevel()
self.golf_quiz_box.protocol('WM_DELETE_WINDOW', partial(self.close_golf_quiz_game, partner))
self.golf_quiz_frame = Frame(self.golf_quiz_box)
self.golf_quiz_frame.grid()
self.golf_quiz_heading = Label(self.golf_quiz_frame, text="Golf Quiz game",
font="arial 18 bold", padx=10, pady=10)
self.golf_quiz_heading.grid(row=0)
self.golf_quiz_history_help_dismiss_buttons_frame = Frame(self.golf_quiz_frame)
self.golf_quiz_history_help_dismiss_buttons_frame.grid(row=6, pady=10)
self.help_button = Button(self.golf_quiz_history_help_dismiss_buttons_frame, text="Help", font="Arial 10 bold",command=self.Help, padx=10, pady=10)
self.help_button.grid(row=6, column=1, padx=5)
def close_golf_quiz_game(self, partner):
partner.golf_quiz_welcome_screen_button.config(state=NORMAL)
self.golf_quiz_box.destroy()
def Help(self):
get_help = Help(self)
class Help:
def __init__(self, partner):
partner.help_button.config(state=DISABLED)
self.help_box = Toplevel()
self.help_box.protocol('WM_DELETE_WINDOW', partial(self.close_Help, partner))
self.help_frame = Frame(self.help_box)
self.help_frame.grid()
self.help_heading = Label(self.help_frame, text="Help", font="arial 18 bold")
self.help_heading.grid(row=0)
self.help_text = Label(self.help_frame, text="Test",
width=60, wrap=400)
self.help_text.grid(row=1)
self.help_button = Button(self.help_frame, text="Dismiss", width=10, font="Arial 10 bold", command=partial(self.close_Help, partner), padx=10, pady=10)
self.help_button.grid(row=2, pady=10)
def close_Help(self, partner):
if partner.help_button.winfo_exists():
partner.help_button.config(state=NORMAL)
self.help_box.destroy()
# main routine
if __name__ == "__main__":
root = Tk()
root.title("quiz game")
something = Welcome_Screen(root)
root.mainloop()
Here is how you can do that (this is also the size (linewise (approx.)) of the minimal reproducible example which you should have provided):
from tkinter import Tk, Toplevel, Button
def close_top(top):
btn.config(state='normal')
top.destroy()
def open_help():
btn.config(state='disabled')
top = Toplevel(root)
top.protocol('WM_DELETE_WINDOW', lambda: close_top(top))
top.focus_force()
# put the rest of help stuff here
root = Tk()
btn = Button(root, text='Help', command=open_help)
btn.pack()
root.mainloop()
Class based approach:
from tkinter import Tk, Toplevel, Button
# this would be the window from where you open the help window
class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
self.btn = Button(self, text='Help',
command=lambda: self.open_help(self.btn))
self.btn.pack()
def open_help(self, btn):
HelpWindow(self, btn)
# this would be the help window
class HelpWindow(Toplevel):
def __init__(self, master, button):
Toplevel.__init__(self, master)
self.button = button
self.button.config(state='disabled')
self.focus_force()
self.protocol('WM_DELETE_WINDOW', self.close)
def close(self):
self.button.config(state='normal')
self.destroy()
MainWindow().mainloop()
Few things:
First of you can simply inherit from container and window classes that way you don't have to separately create them in the class and you can easily reference them in the class using just self
.focus_force() does what it says, it forces focus on the widget
Important (suggestions)
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.
I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case, class names in CapitalCase. Don't have space around = if it is used as a part of keyword argument (func(arg='value')) but use if it is used for assigning a value (variable = 'some value'). Have two blank lines around function and class declarations.
You need to make use of class variables inside golf_quiz_game in order to have only one instance of Help window:
class golf_quiz_game:
# class variables
_help_button = None # reference to instance "Help" button
_help_win = None # reference to instance "Help" window
def __init__(self, partner):
...
# set button state based on whether "Help" window is open or not
self.help_button.config(state="normal" if self.__class__._help_win is None else "disabled")
# update class reference of "Help" button
self.__class__._help_button = self.help_button
def close_golf_quiz_game(self, partner):
partner.golf_quiz_welcome_screen_button.config(state=NORMAL)
self.golf_quiz_box.destroy()
# update class reference of "Help" button
self.__class__._help_button = None
def Help(self):
if self.__class__._help_win is None:
# no "Help" window is open, create one
self.__class__._help_win = Help(self)
def help_closed(self):
if self.__class__._help_button:
# enable the "Help" button
self.__class__._help_button.config(state="normal")
# update "Help" window status
self.__class__._help_win = None
class Help:
...
def close_Help(self, partner):
self.help_box.destroy()
# notify partner that "Help" window is closed
partner.help_closed()
I want to have a tkinter window that displays both a cronometer and a sudoku. The cronometer is a class, so how can I add it to the window that displays the sudoku?
I already managed to get two separate windows, but I couldn't make one with both things.
def GUI4x4(dif): #This function gets just called from other place
# What I want is to be able to display this class
# Cronometer in the main window that's created below
class Cronometer():
...
def __init__(self):
self.crono=Tk()
self.tiempo = StringVar()
self.tiempo.set("00:00:00")
self.label = Label(self.crono,textvariable=self.tiempo, bg="white")
self.label.grid(column=0,row=0)
self.label.configure(font=("Times 13 bold"))
self.btnI = Button(self.crono, bg="white", text="Start",command=self.iniciarT,font=("Times 11"))
self.btnI.grid(pady=3,column=0,row=1)
self.btnP = Button(self.crono, bg="white", text="Pause",command=self.pausarT,font=("Times 11"))
self.btnP.grid(pady=3,column=0,row=2)
self.btnR = Button(self.crono, bg="white", text="Restart",command=self.reiniciarT,font=("Times 11"))
self.btnR.grid(pady=3,column=0,row=3)
GUI = Tk() # This creates the main window, and places
# 34 buttons in it
...
# Defining the Buttons
btn00 = Button(GUI, text=Tablero[0][0], width=5, height=3, activebackground="lime")
btn01 = Button(GUI, text=Tablero[0][1], width=5, height=3, activebackground="lime")
btn02 = Button(GUI, text=Tablero[0][2], width=5, height=3, activebackground="lime")
...
btn33 = Button(GUI, text=Tablero[3][3], width=5, height=3, activebackground="lime")
#Placing the 34 buttons
btn00.grid(row=0, column=0)
btn01.grid(row=0, column=1)
btn02.grid(row=0, column=2)
...
btn33.grid(row=3, column=3)
The standard way to deal with this with tkinter is that each "widget" in the application is its own class based on the tkinter Frame widget, one class for the chrono, another for the sudoko game. There might even be a main app class.
Advantage of this method is that each widget frame can be created independently and then joined together later. These classes might also be split up in to separate code files.
A fairly simple example below
import tkinter as tk
class Chromometer(tk.Frame):
def __init__(self,master=None,**kw):
tk.Frame.__init__(self,master=master,**kw)
self.tiempo = tk.StringVar()
self.tiempo.set("00:00:00")
self.label = tk.Label(self,textvariable=self.tiempo, bg="white")
self.label.grid(column=0,row=0)
class Sudoko(tk.Frame):
def __init__(self,master=None,**kw):
tk.Frame.__init__(self,master=master,**kw)
self.label = tk.Label(self,text="Sudoko", bg="white")
self.label.grid(column=0,row=0)
class MainApp(tk.Frame):
def __init__(self,master=None,**kw):
tk.Frame.__init__(self,master=master,**kw)
self.chrono = Chromometer(master=self)
self.chrono.grid()
self.sudoko = Sudoko(master=self)
self.sudoko.grid()
if __name__ == '__main__':
root = tk.Tk()
app = MainApp(master=root)
app.grid()
root.mainloop()
Each class will have their own methods to perform the functionality needed by each. The chromo/chrono class will have a method to update the timer.
Learning to use Tkinter and following an online tutorial. This is an example given where text is entered and then label will update accordingly to the input text field.
I'm trying it in Python3 on Mac and on Raspberry Pi and I don't see the effect of trace, hence the label doesn't get modified by the Entry. Any help would be appreciate (or any other simple example of how to use Entry and Trace together)
Thanks.
from tkinter import *
class HelloWorld:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(
frame, text="Hello", command=self.button_pressed
)
self.button.pack(side=LEFT, padx=5)
self.label = Label(frame, text="This is a label")
self.label.pack()
a_var = StringVar()
a_var.trace("w", self.var_changed)
self.entry = Entry(frame,textvariable=a_var)
self.entry.pack()
def button_pressed(self):
self.label.config(text="I've been pressed!")
def var_changed(self, a, b, c):
self.label.config(text=self.entry.get())
def main():
root = Tk()
root.geometry("250x150+300+300")
ex = HelloWorld(root)
root.mainloop()
if __name__ == '__main__':
main()
The problem is that you are using a local variable for a_var, and on the Mac it is getting garbage-collected. Save a reference to the variable (eg: self.a_var rather than just a_var).
self.a_var = StringVar()
self.a_var.trace("w", self.var_changed)
self.entry = Entry(frame,textvariable=self.a_var)
self.entry.pack()
Note: if all you want is to keep a label and entry in sync, you don't need to use a trace. You can link them by giving them both the same textvariable:
self.entry = Entry(frame, textvariable=self.a_var)
self.label = Label(frame, textvariable=self.a_var)
Please help! It comes up with an error saying that there is a missing "Self" and I cant find it. I have tried everything and i cant find the error.
from tkinter import *
import tkinter
class App:
def __init__(self):
self.master = tkinter.Tk()
self.master.title("Encrypter & Decrypter")
def E_Entry(self):
print(self.E_Entry.get(self))
self.E_Question = Label(self.master, text="Encrypter",)
self.E_Question.grid(row=1, column=1, sticky=E)
self.E_Entry = Entry(self.master, width = 25)
self.E_Entry.grid(row=1, column=2)
self.E_Button = Button(self.master, text="Encrypt", command=E_Entry)
self.E_Button.grid(row=1, column=3)
self.D_Question = Label(self.master, text="Decrypter",)
self.D_Question.grid(row=2, column=1, sticky=E)
self.D_Entry = Entry(self.master, width = 25)
self.D_Entry.grid(row=2, column=2)
self.D_Button = Button(self.master, text="Decrypt")
self.D_Button.grid(row=2, column=3)
self.master.mainloop()
App()
You should not have a function with the same name as the widget, the indentation of the function is incorrect, and you are calling it incorrectly.
It should be something like this:
class App:
def __init__(self):
...
self.E_Button = Button(..., command=self.print_e)
...
def print_e(self):
print(self.E_Entry.get())
On the line where it says:
App()
You should have assigned the resulting object to a variable, such as:
my_app = App()
So I am currently trying to create a button on a GUI that will let the user generate a new entry field.
I have no idea how to do this. I'm guessing that it will require a lambda function, but apart from that, I have no idea.
Here's the basic code I have so far:
from tkinter import *
class prac:
def autoAddWidget(self,frame,x,y):
self.entryField = Entry(frame,text="Entry Field")
self.entryField.grid(row=x, column=y)
#lambda function?
def __init__(self, master):
frame = Frame(master, width=60, height=50)
frame.pack()
x=1
self.addWidgetButton = Button(frame, text="Add new widget", command=self.autoAddWidget(frame, x,0))
self.addWidgetButton.grid(row=0, column=0)
x+=1
root = Tk()
app = prac(root)
root.mainloop()
Would appreciate the help.
Thanks
You're passing to the command argument result from the method self.autoAddWidget(frame, x,0) not method itself. You have to pass there a reference to a callable object, a function that will be called when the event occurs. Please check a documentation next time before you ask the question.
Ok, I fixed the code, now it works:
from tkinter import *
class Prac:
def autoAddWidget(self):
self.entryField = Entry(self.frame,text="Entry Field")
self.entryField.grid(row=self.x, column=0)
self.x+=1
def __init__(self, master):
self.frame = Frame(master, width=60, height=50)
self.frame.pack()
self.x=1
self.addWidgetButton = Button(self.frame, text="Add new widget", command=self.autoAddWidget)
self.addWidgetButton.grid(row=0, column=0)
root = Tk()
app = Prac(root)
root.mainloop()