Create label in tkinter and update the Label with an int variable - python

I want to create a label and update it with the int-value, which is updated by pressing the buttons, also in the label. I'm still new to Python and would like some help :)
import tkinter as tk
class Main(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.integer = tk.IntVar()
self.integer.set(0)
tk.Button(self, text='Quit', command=self.destroy).pack()
tk.Button(self, text='+', command=self.plus_one).pack()
tk.Button(self, text='-', command=self.take_one).pack()
self.entry0 = tk.Entry(self, textvariable=str(self.integer), justify="center", width=4)
self.entry0.pack()
def plus_one(self):
x = self.integer.get() + 1
self.integer.set(x)
def take_one(self):
x = self.integer.get() - 1
self.integer.set(x)
app = Main()
app.mainloop()

You would do this the same way you did with the Entry widget:
import tkinter as tk
class Main(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.integer = tk.IntVar()
self.integer.set(0)
tk.Button(self, text='Quit', command=self.destroy).pack()
tk.Button(self, text='+', command=self.plus_one).pack()
tk.Button(self, text='-', command=self.take_one).pack()
self.entry0 = tk.Entry(self, textvariable=str(self.integer), justify="center", width=4)
self.entry0.pack()
self.label0 = tk.Label(self, textvariable=str(self.integer))
self.label0.pack()
def plus_one(self):
x = self.integer.get() + 1
self.integer.set(x)
def take_one(self):
x = self.integer.get() - 1
self.integer.set(x)
app = Main()
app.mainloop()
As per your comments, if you are interested in having the binding at button press instead of button release, this has been already addressed here.

Related

tkinter: LabelFrame in a separate TopLevel window

My "simple" intention is to create a Dialog - launched by a button - where I have several LabelFrames with their radio button.
I tried with 1 LabelFrame with this simple code the radios appear in the main window, not in the dialogue one !!!! I cannot understand why. Please help.. ty for your attention
Here's the code:
import tkinter as tk
from tkinter import ttk
class PersonEmptyDocsDialog(tk.Toplevel):
def __init__(self, root,personid):
super().__init__(root)
self.personid = personid
self.code = tk.StringVar()
frame1 = ttk.Labelframe(self,text='testo').grid(column=0,row=0,padx=20,pady=20)
ttk.Radiobutton(frame1, text="Option 1", variable=self.code, value="0-0-0").pack()
ttk.Radiobutton(frame1, text="Option 1", variable=self.code, value="0-0-1").pack()
ttk.Radiobutton(frame1, text="Option 1", variable=self.code, value="0-0-2").pack()
self.ok_button = tk.Button(self, text="OK", command=self.on_ok).grid(column=0,row=1)
#self.ok_button.pack()
def on_ok(self, event=None):
self.destroy()
def show(self):
self.wm_deiconify()
self.wait_window()
return self.code.get()
class Example():
def __init__(self, root):
mainframe = ttk.Frame(root).pack(fill="both", expand=True)
self.root = root
ttk.Button(mainframe, text="Get Input", command=self.on_button).pack(padx=8, pady=8)
ttk.Label(mainframe, text="", width=20).pack(side="bottom", fill="both", expand=True)
def on_button(self):
string = PersonEmptyDocsDialog(self.root, 12).show()
print(string)
root = tk.Tk()
root.wm_geometry("400x200")
Example(root)
root.mainloop()
You cannot put in one line. You need to break this into in line 11
frame1 = ttk.Labelframe(self,text='testo')
frame1.grid(column=0,row=0,padx=20,pady=20)
Output:
Output after clicking Get input button:

Tkinter Button does nothing when clicked

This is the code for my personal project, for some reason, I can't get the button to do anything when pressed.
Edit: So I managed to fix the text deleting after each input, so now it will continue to output as many passwords as I want. I removed the 0.0 in output.delete so it doesn't default the text to 0 after each generated password.
from tkinter import *
from datetime import datetime
import pyperclip as pc
def close_window():
window.destroy()
exit()
# Main GUI program
window = Tk()
window.frame()
window.grid_rowconfigure((0, 1), weight=1)
window.grid_columnconfigure((0, 1), weight=1)
window.title("PW Gen")
window.geometry('+10+10')
window.configure(background="black")
Label(window, bg="black", height=0, width=25, font="Raleway").grid(row=1, column=0, sticky=NSEW)
# Enter the last 4 and generate the password
Label(window, text="Enter the last 4 digits of the Reader Name:", bg="black", fg="white", font="Raleway 12 bold").grid(row=1, column=0, sticky=W)
textentry = Entry(window, width=53, bg="white")
textentry.grid(row=2, column=0, sticky=W)
Button(window, text="Generate Password", width=16, font="Raleway 8 bold", command=click).grid(row=3, column=0, sticky=W)
# Output the password
Label(window, text="\nPassword", bg="black", fg="white", font="Raleway 12 bold").grid(row=4, column=0, sticky=W)
output = Text(window, width=40, height=4, wrap=WORD, background="white")
output.grid(row=5, column=0, columnspan=2, sticky=W)
# Button and Text To Quit GUI
Label(window, text="Click to Quit", bg="black", fg="white", font="Raleway 12 bold").grid(row=6, column=0, sticky=W)
Button(window, text="Quit", width=14, font="Raleway 8 bold", command=close_window).grid(row=7, column=0, sticky=W)
window.mainloop()
Not exactly the best solution but you can definitely give it a try.
import tkinter as tk
from datetime import datetime
import string
import pyperclip as pc
import random
root = tk.Tk()
root.title("PW Gen")
root.geometry('+10+10')
mainframe = tk.Frame(root)
text = tk.Text(root, height=5, width=25, font="Raleway")
def pwgen():
last4=text.get('1.0','end')[-5:]
j=[char for char in last4 if char in string.ascii_uppercase or char in string.ascii_lowercase]
print(j)
random.shuffle(j)
print(j)
today = datetime.today()
pw = int(today.strftime("%d")) * int(today.strftime("%m"))
last4=''.join(j)
pwgen = "$ynEL" + str(pw) + str()
pc.copy(pwgen)
print("\nThe password is $ynEL" + str(pw) + str(last4))
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.quit1 = tk.Button(self, text="QUIT", fg="black", command=self.master.destroy)
self.quit1.pack(side="top")
text.pack(side="bottom")
self.b2 = tk.Button(self)
self.create_widgets()
self.pack()
def create_widgets(self):
self.b2["text"] = "GenPW"
self.b2["command"] = pwgen
self.b2.pack(side="left")
def b1(self):
self.b2 = tk.Button(self, text="Generate PW", command=pwgen)
app = Application(root)
root.mainloop()
The code has many problems.
mainframe is not shown and never used.
Text is shown, but never used.
Text is packed inside Application but is not part of Application.
pwgen uses input and no GUI widget. A infinte loop with a GUI application is not good.
You should use the attributes of a datetime directly.
You should not generate the password at two places in the code.
You should not name a local variable like the function.
In Application you are using b1 as method, this method is overloaded by the attribute b1, so you cannot use the method anymore.
In the method b1 you are generating a new butten instead of calling the function pwgen.
import tkinter as tk
from datetime import datetime
import pyperclip as pc
def pwgen():
today = datetime.today()
pw = today.day * today.month
last4 = input("Last 4 of Reader Name [****] ")
password = f"$ynEL{pw}{last4}"
pc.copy(password)
print("\nThe password is", password)
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.quit = tk.Button(self, text="QUIT", fg="black", command=self.master.destroy)
self.quit.pack(side="top")
self.b1 = tk.Button(self, text="GenPW", command=self.click_b1)
self.b1.pack(side="left")
def click_b1(self):
pwgen()
def main():
root = tk.Tk()
root.title("PW Gen")
root.geometry('+10+10')
text = tk.Text(root, height=5, width=25, font="Raleway")
text.pack(side="bottom")
app = Application(master=root)
app.pack()
root.mainloop()
if __name__ == "__main__":
main()
This works. I have used grid manager for more control and removed unused code.
import tkinter as tk
from tkinter import *
from datetime import datetime
import pyperclip as pc
root = tk.Tk()
root.title("PW Gen")
root.geometry('+10+10')
Text = tk.Text(root, height=5, width=25, font="Raleway")
def pwgen():
while True:
today = datetime.today()
pw = int(today.strftime("%d")) * int(today.strftime("%m"))
last4 = input("Last 4 of Reader Name [****] ")
pwgen = "$ynEL" + str(pw) + str(last4)
pc.copy(pwgen)
print("\nThe password is $ynEL" + str(pw) + str(last4))
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.quit = tk.Button(self, text="QUIT", fg="black", command=self.master.destroy)
self.quit.grid(row=0,column=0,sticky=tk.EW)
Text.grid(row=1,column=0,sticky=tk.NSEW)
self.b1 = tk.Button(self, text="Generate PW", command=pwgen)
self.b1.grid(row=0,column=1,sticky=tk.EW)
self.grid(row=0,column=0,sticky=tk.NSEW)
app = Application(master=root)
root.mainloop()
A previous version created multiple Generate PW buttons.

What is a good way to stop 2 labels in the same row and column from covering each other in tkinter?

When button 1 is pressed I want this program to say word 'hi' and when button 2 is pressed I want it to say 'goodbye' in the same spot as it says hi and override what button 1 produced. However, it doesn't override it just merges the 2 labels together. What is a good way to prevent this from happening while making sure both labels appear in the same spot?
from tkinter import *
root = Tk()
def press():
word = Label(root, text='hi')
word.grid(row=0, column=1)
def press_2():
word_2 = Label(root, text='goodbye')
word_2.grid(row=0, column=1)
button_1 = Button(root, text=1, command=press)
button_2 = Button(root, text=2, command=press_2)
button_1.grid(row=0, column=0)
button_2.grid(row=1, column=0)
root.mainloop()
You just need to use one Label and keep changing its text. We can do this efficiently by using a lambda for the widget command. As stated by #Bryan Oakley, using a StringVar adds unnecessary overhead. This is a slightly modified version from my original. In this version we use the config method of the widget to set the text. As a bonus the code is formatted with a class structure. Using a procedural style with tkinter eventually turns into a big mess. Considering the required imports are minimal, we import them directly and do not need to prefix every widget.
from tkinter import Tk, Button, Label
class Application(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
lbl = Label(self, text='hi')
lbl.grid(row=0, column=1)
btn1 = Button(self, text='1',)
btn1.config(command=lambda m='hi': lbl.config(text=m))
btn1.grid(row=0, column=0)
btn2 = Button(self, text='2')
btn2.config(command=lambda m='goodbye': lbl.config(text=m))
btn2.grid(row=1, column=0)
if __name__ == "__main__":
app = Application()
app.minsize(100, 50)
app.title("My Application")
app.mainloop()
from tkinter import *
root = Tk()
def press():
label['text'] = "hi"
def press_2():
label['text'] = "goodbye"
label = Label(root)
label.grid(row=0, column=1)
button_1 = Button(root, text=1, command=press)
button_2 = Button(root, text=2, command=press_2)
button_1.grid(row=0, column=0)
button_2.grid(row=1, column=0)
root.mainloop()
Put it on the windows firstly,Then change the text config.
A better way to do so would be by using config() method of widgets. But here i dont know if its gonna help out much. But give it a try
from tkinter import *
root = Tk()
def press():
word.config(text='hi')
def press_2():
word.config(text='goodbye')
button_1 = Button(root, text=1, command=press)
button_2 = Button(root, text=2, command=press_2)
button_1.grid(row=0, column=0)
button_2.grid(row=1, column=0)
word = Label(root, text='') #creating a blank label to edit later on in functions
word.grid(row=0, column=1)
root.mainloop()

Tkinter Reading Input Value from PopUp

Creating a popup window which will ask for email entry and then print the email when 'OK' is pressed, this is my code:
import tkinter as tk
class PopUp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Label(self, text="Main Window").pack()
popup = tk.Toplevel(self)
popup.wm_title("EMAIL")
popup.tkraise(self)
tk.Label(popup, text="Please Enter Email Address").pack(side="left", fill="x", pady=10, padx=10)
self.entry = tk.Entry(popup, bd=5, width=35).pack(side="left", fill="x")
self.button = tk.Button(popup, text="OK", command=self.on_button)
self.button.pack()
def on_button(self):
print(self.entry.get())
app = PopUp()
app.mainloop()
Every time I run it I get this error:
AttributeError: 'NoneType' object has no attribute 'get'
The pop up works how it should but its the input entry that doesn't seem to be working.
I've seen this example before but it wasn't in the popup (I can get it work perfectly without the popup).
Any help is appreciated.
You can store the value in a StringVar variable and get() its value.
import tkinter as tk
from tkinter import StringVar
class PopUp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Label(self, text="Main Window").pack()
popup = tk.Toplevel(self)
popup.wm_title("EMAIL")
popup.tkraise(self)
tk.Label(popup, text="Please Enter Email Address").pack(side="left", fill="x", pady=10, padx=10)
self.mystring = tk.StringVar(popup)
self.entry = tk.Entry(popup,textvariable = self.mystring, bd=5, width=35).pack(side="left", fill="x")
self.button = tk.Button(popup, text="OK", command=self.on_button)
self.button.pack()
def on_button(self):
print(self.mystring.get())
app = PopUp()
app.mainloop()

Trouble defining 'textvariable' in self-reference implementation of tkinter

I have repeatedly tried, and failed, to understand where and how I should be defining the textvariable "die" in the following code. The commented lines are where I've tried assigning values, but a variety of Value or Name errors keep occurring, which leads me to believe that I don't know how to properly initialize its value.
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
#die = StringVar() # 1
def roll (int):
try:
die.set(randrange(1,int))
except ValueError:
pass
class Application(ttk.Frame):
#die = StringVar() # 2
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
#self.die = StringVar() # 3
self.createWidgets()
def createWidgets(self):
#self.die = StringVar() # 4
self.d_twoButton = ttk.Button(self, text='d2', command=roll(2)).grid()
self.d_threeButton = ttk.Button(self, text='d3', command=roll(3)).grid()
self.d_fourButton = ttk.Button(self, text='d4', command=roll(4)).grid()
self.d_sixButton = ttk.Button(self, text='d6', command=roll(6)).grid()
self.d_eightButton = ttk.Button(self, text='d8', command=roll(8)).grid()
self.d_tenButton = ttk.Button(self, text='d10', command=roll(10)).grid()
self.d_twelveButton = ttk.Button(self, text='d12', command=roll(12)).grid()
self.d_twentyButton = ttk.Button(self, text='d20', command=roll(20)).grid()
self.d_onehundredButton = ttk.Button(self, text='d100', command=roll(100)).grid()
self.resultLabel = ttk.Label(self, textvariable=die)
self.resultLabel.grid()
app = Application()
app.master.title('Die Roller')
#app.die = StringVar() # 5
app.mainloop()
(I had tried to add the tags for textvariable and stringval for easier identification, but I am as of yet unable. If anyone is able to add such tags to this post, please feel free to do so.)
Spot #3 is probably the best place. You'll need to make a few additional modifications, though.
You'll have to explicitly refer to the app object in roll, to access its die attribute. Alternatively, roll should be a method of the Application class; see second code block.
command parameters must be wrapped in a lambda, if you're supplying arguments to the function you want it to call.
optional: remove all the self.d_someNumberButton = assignment bits, since they're all None and you don't use them anywhere anyway. (Hint: my_thing = Button() makes my_thing into a Button. my_thing = Button().grid() makes my_thing into None.)
Implementation with the fewest possible modifications to your original code:
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
#die = StringVar() # 1
def roll (int):
try:
app.die.set(randrange(1,int))
except ValueError:
pass
class Application(ttk.Frame):
#die = StringVar() # 2
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.die = StringVar() # 3
self.createWidgets()
def createWidgets(self):
#self.die = StringVar() # 4
self.d_twoButton = ttk.Button(self, text='d2', command=lambda: roll(2)).grid()
self.d_threeButton = ttk.Button(self, text='d3', command=lambda: roll(3)).grid()
self.d_fourButton = ttk.Button(self, text='d4', command=lambda: roll(4)).grid()
self.d_sixButton = ttk.Button(self, text='d6', command=lambda: roll(6)).grid()
self.d_eightButton = ttk.Button(self, text='d8', command=lambda: roll(8)).grid()
self.d_tenButton = ttk.Button(self, text='d10', command=lambda: roll(10)).grid()
self.d_twelveButton = ttk.Button(self, text='d12', command=lambda: roll(12)).grid()
self.d_twentyButton = ttk.Button(self, text='d20', command=lambda: roll(20)).grid()
self.d_onehundredButton = ttk.Button(self, text='d100', command=lambda: roll(100)).grid()
self.resultLabel = ttk.Label(self, textvariable=self.die)
self.resultLabel.grid()
app = Application()
app.master.title('Die Roller')
#app.die = StringVar() # 5
app.mainloop()
Result:
Here, I just clicked the "d100" button, and it successfully displayed a number in the expected range.
Alternative implementation, using roll as a class method:
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
class Application(ttk.Frame):
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.die = StringVar()
self.createWidgets()
def createWidgets(self):
ttk.Button(self, text='d2', command=lambda: self.roll(2)).grid()
ttk.Button(self, text='d3', command=lambda: self.roll(3)).grid()
ttk.Button(self, text='d4', command=lambda: self.roll(4)).grid()
ttk.Button(self, text='d6', command=lambda: self.roll(6)).grid()
ttk.Button(self, text='d8', command=lambda: self.roll(8)).grid()
ttk.Button(self, text='d10', command=lambda: self.roll(10)).grid()
ttk.Button(self, text='d12', command=lambda: self.roll(12)).grid()
ttk.Button(self, text='d20', command=lambda: self.roll(20)).grid()
ttk.Button(self, text='d100', command=lambda: self.roll(100)).grid()
self.resultLabel = ttk.Label(self, textvariable=self.die)
self.resultLabel.grid()
def roll(self, max_value):
app.die.set(randrange(1,max_value))
app = Application()
app.master.title('Die Roller')
app.mainloop()
Alternative alternative implementation that uses a for loop to create the buttons:
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
class Application(ttk.Frame):
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.die = StringVar()
self.createWidgets()
def createWidgets(self):
for num_sides in [2, 3, 4, 6, 8, 10, 12, 20, 100]:
ttk.Button(self, text="d{}".format(num_sides), command=lambda value=num_sides: self.roll(value)).grid()
self.resultLabel = ttk.Label(self, textvariable=self.die)
self.resultLabel.grid()
def roll(self, max_value):
app.die.set(randrange(1,max_value))
app = Application()
app.master.title('Die Roller')
app.mainloop()

Categories