I'm unable to get a string out of tkinter entrybox - python

import random
import tkinter as tk
frame = tk.Tk()
frame.title("koeweils baldadige encyptor")
frame.geometry('400x200')
printButton = tk.Button(frame,text = "Print", command = lambda: zandkasteel())
printButton.pack()
freek = tk.Text(frame,height = 5, width = 20)
freek.pack()
input_a = freek.get(1.0, "end-1c")
print(input_a)
fruit = 0
fad = input_a[fruit:fruit+1]
print(fad)
schepje = len(input_a.strip("\n"))
print(schepje)
def zandkasteel():
lbl.config(text = "Ingevulde string: "+input_a)
with open("luchtballon.txt", "w") as chocoladeletter:
for i in range(schepje):
n = random.randint()
print(n)
leuk_woord = ord(fad)*n
print(leuk_woord)
chocoladeletter.write(str(leuk_woord))
chocoladeletter.write(str(n))
chocoladeletter.write('\n')
lbl = tk.Label(frame, text = "")
lbl.pack()
frame.mainloop()
I need to get the string that was entered into the text entry field freek. I have tried to assign that string to input_a, but the string doesn't show up.
Right now, input_a doesn't get anything assigned to it and seems to stay blank. I had the same function working before implementing a GUI, so the problem shouldn't lie with the def zandkasteel.
To be honest I really don't know what to try at this point, if you happen to have any insights, please do share and help out this newbie programmer in need.

Here are some simple modifications to your code that shows how to get the string in the Text widget when it's needed — specifically when the zandkasteel() function gets called in response to the user clicking on the Print button.
import random
import tkinter as tk
frame = tk.Tk()
frame.title("koeweils baldadige encyptor")
frame.geometry('400x200')
printButton = tk.Button(frame, text="Print", command=lambda: zandkasteel())
printButton.pack()
freek = tk.Text(frame, height=5, width=20)
freek.pack()
def zandkasteel():
input_a = freek.get(1.0, "end-1c")
print(f'{input_a=}')
fruit = 0
fad = input_a[fruit:fruit+1]
print(f'{fad=}')
schepje = len(input_a.strip("\n"))
print(f'{schepje=}')
lbl.config(text="Ingevulde string: " + input_a)
with open("luchtballon.txt", "w") as chocoladeletter:
for i in range(schepje):
n = random.randint(1, 3)
print(n)
leuk_woord = ord(fad)*n
print(leuk_woord)
chocoladeletter.write(str(leuk_woord))
chocoladeletter.write(str(n))
chocoladeletter.write('\n')
lbl = tk.Label(frame, text="")
lbl.pack()
frame.mainloop()

Related

How to correctly define variables in Python?

Im writing a program so i can practise my spanish grammer. I come from the world of PLC programming and wanted to delve into Python to get 2 birds stoned at once. Below is the code, it however gives me an error on the syntax as its missing the var RandomVerbNumber in the on_change def. I have tried defining it outside of the def structures, but it will always make RandomVerbNumber have an incorrect value.
I have tried looking into classes and the init function. But that's not very clear to me yet.
import gspread
import random
import tkinter as tk
gc = gspread.service_account(filename = 'credentials.json')
SpanishVerbs = gc.open('Spanish Verbs')
worksheet = SpanishVerbs.worksheet("EnglishSpanishList")
EnglishList = worksheet.col_values(1)
SpanishList = worksheet.col_values(2)
AmountOfRows = len(worksheet.col_values(1))
def on_next(event):
RandomVerbNumber = random.randint(0,AmountOfRows)
EnglishVerbLabel.config(text = EnglishList[RandomVerbNumber])
print(EnglishList[RandomVerbNumber]," = ",SpanishList[RandomVerbNumber])
def on_change(event):
if SpanishEntry.get() == SpanishList[RandomVerbNumber]:
ResultLabel.config(text = "Correct")
else:
ResultLabel.config(text = "Incorrect")
SpanishEntry.delete(0, tk.END)
root = tk.Tk()
QuestionLabel = tk.Label(root, text = "Spanish Verb for:")
EnglishVerbLabel = tk.Label(root)
ResultLabel = tk.Label(root)
SpanishEntry = tk.Entry(root)
root.bind("<Return>", on_change)
buttonNext = tk.Button(root, text="Next", fg="black")
buttonNext.bind("<Button-1>", on_next)
QuestionLabel.grid(row=0, sticky=tk.E)
EnglishVerbLabel.grid(row=0, column=1)
SpanishEntry.grid(row=1, columnspan=2)
buttonNext.grid(row=2, columnspan=2)
ResultLabel.grid(row=3, columnspan=2)
root.mainloop()
RandomVerbNumber is not defined in the function on_change. Why do you think it would be defined?
There does exist a variabel RandomVerbNumber in another function, but that's outside of the scope of on_change. Variables only exists within their scope.
You can pass a randomised array defined in main as an argument into both methods, holding the index values of the words and pop the index value in the on_next method. Your edited code is below, my edits are marked with NOTE tags.
This method works because python lists are passed by reference.
import gspread
import random
import tkinter as tk
gc = gspread.service_account(filename = 'credentials.json')
SpanishVerbs = gc.open('Spanish Verbs')
worksheet = SpanishVerbs.worksheet("EnglishSpanishList")
EnglishList = worksheet.col_values(1)
SpanishList = worksheet.col_values(2)
AmountOfRows = len(worksheet.col_values(1))
#NOTE:
randomisedList = random.sample(range(AmountOfRows), AmountOfRows)
#NOTE: event argument removed
def on_next(list):
EnglishVerbLabel.config(text = EnglishList[RandomVerbNumber])
print(EnglishList[RandomVerbNumber]," = ",SpanishList[RandomVerbNumber])
list.pop()
#NOTE: event argument removed
def on_change(list):
#NOTE:
if SpanishEntry.get() == SpanishList[list[-1]]:
ResultLabel.config(text = "Correct")
else:
ResultLabel.config(text = "Incorrect")
SpanishEntry.delete(0, tk.END)
root = tk.Tk()
QuestionLabel = tk.Label(root, text = "Spanish Verb for:")
EnglishVerbLabel = tk.Label(root)
ResultLabel = tk.Label(root)
SpanishEntry = tk.Entry(root)
#NOTE:
root.bind("<Return>", lambda event, list=randomisedList: on_change(list))
buttonNext = tk.Button(root, text="Next", fg="black")
#NOTE:
buttonNext.bind("<Button-1>", lambda event, list=randomisedList: on_next(list))
QuestionLabel.grid(row=0, sticky=tk.E)
EnglishVerbLabel.grid(row=0, column=1)
SpanishEntry.grid(row=1, columnspan=2)
buttonNext.grid(row=2, columnspan=2)
ResultLabel.grid(row=3, columnspan=2)
root.mainloop()

Change (update) text in Python Tkinter widgets

I am trying to update information in tkinter labels and buttons without redrawing entire screens. I'm using Python 3, a Raspberry Pi, and Idle. I have a trivial example of what I am trying to do. I see comments here that suggest I need to learn to manipulate stringvariable or IntVar, etc. but my book is totally unhelpful in that regard. In this example, I would like the number between the buttons to track the value of the number as it changes with button pushes.
##MoreOrLess.01.py
from tkinter import *
global number
number = 5
root = Tk()
root.title("Test Buttons")
def Less():
global number
number -= 1
print ("The number is now ", number)
def More():
global number
number += 1
print("The number is now ", number)
def MakeLabel(number):
textvariable = number
label1 = Label(root, text = "Pick a button please.").pack(pady=10)
btnL = Button(root, text = "More", command = More).pack(side = LEFT)
btnR = Button(root, text = "Less", command = Less).pack(side = RIGHT)
label2 = Label(root, text = number).pack(pady = 20)
MakeLabel(number)
Not only do you base yourself in a book, check the official documentation of tkinter. in your case you must create a variable of type IntVar with its set() and get() method, and when you want to link that variable through textvariable.
from tkinter import *
root = Tk()
root.title("Test Buttons")
number = IntVar()
number.set(5)
def Less():
number.set(number.get() - 1)
print ("The number is now ", number.get())
def More():
number.set(number.get() + 1)
print("The number is now ", number.get())
def MakeLabel(number):
textvariable = number
label1 = Label(root, text = "Pick a button please.").pack(pady=10)
btnL = Button(root, text = "More", command = More).pack(side = LEFT)
btnR = Button(root, text = "Less", command = Less).pack(side = RIGHT)
label2 = Label(root, textvariable = number).pack(pady = 20)
MakeLabel(number)
root.mainloop()

Issues figuring out how to update labels in Tkinter for my Python program

So I am writing a Python program in class that uses the Caesar cipher to take a users input and output it as cipher-text. Since i had a lot more time for this project I planned on giving it a GUI in Tkinter. But when I assign the resulted cipher-text to a label it won't display it and keeps it blank. I'm a noob to python and even more to Tkinter so I'm not too keen on being able to fix these issues myself. Here's the code:
import string
import collections
import random
import tkinter
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("Encoder")
root.geometry("500x400")
def caesar(rotate_string, number_to_rotate_by):
upper = collections.deque(string.ascii_uppercase)
lower = collections.deque(string.ascii_lowercase)
upper.rotate(number_to_rotate_by)
lower.rotate(number_to_rotate_by)
upper = ''.join(list(upper))
lower = ''.join(list(lower))
return rotate_string.translate(str.maketrans(string.ascii_uppercase, upper)).translate(str.maketrans(string.ascii_lowercase, lower))
def callback():
print (code)
b = Button(root, text="get", width=10, command=callback)
b.pack()
var = StringVar()
e = Entry(root, textvariable = var)
e.pack()
our_string = e.get()
random_number = random.randint(1,25)
code = caesar(our_string, random_number)
l = Label(root, textvariable=code, anchor=NW, justify=LEFT, wraplength=398)
l.pack()
l.place(relx=0.5, rely=0.5, anchor=CENTER)
root.mainloop()
There are several issues with the code you've posted. First and foremost, your callback doesn't do anything besides print the code variable. You need to move your call to caesar and the associated code into the callback, like so
def callback():
global code
our_string = e.get()
random_number = random.randint(1, 25)
code.set(caesar(our_string, random_number))
The second issue that I see is that you need to use a StringVar as the textvariable argument in your Label constructor in order to get the label to update automatically. When all is said and done, my version of your code looks like
import string
import collections
import random
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("Encoder")
root.geometry("500x400")
code = StringVar()
code.set('Hello')
def caesar(rotate_string, number_to_rotate_by):
upper = collections.deque(string.ascii_uppercase)
lower = collections.deque(string.ascii_lowercase)
upper.rotate(number_to_rotate_by)
lower.rotate(number_to_rotate_by)
upper = ''.join(list(upper))
lower = ''.join(list(lower))
return rotate_string.translate(str.maketrans(string.ascii_uppercase, upper)).translate(str.maketrans(string.ascii_lowercase, lower))
def callback():
global code
our_string = e.get()
random_number = random.randint(1, 25)
code.set(caesar(our_string, random_number))
b = Button(root, text="get", width=10, command=callback)
b.pack()
var = StringVar()
e = Entry(root, textvariable=var)
e.pack()
l = Label(root, textvariable=code, anchor=NW, justify=LEFT, wraplength=398)
l.pack()
l.place(relx=0.5, rely=0.5, anchor=CENTER)
root.mainloop()
This seems to do what you'd expect.

How would I create a reset button for my program relating with the following code?

I am trying to add a reset button but I can't seem to get it to work. I created a main in order to refer back to it when the button is pressed but no luck. Any ideas?
import sys
from tkinter import *
import math
def main():
def closeWin():
myGui.destroy() #Close Window Function
def kiloFunc():
myText = kiloMent.get() #Kilometers to Miles Fuction
convert = 0.62
miles = myText * convert
finalKilo = Label(text = miles,fg='red',justify='center').place(x=200,y=80)
def mileFunc():
myText2 = mileMent.get() #Miles to Kilometers Function
convertTwo = myText2 // 0.62
finalMile = Label(text = convertTwo, fg = 'red',justify='center').place(x=200,y=170)
myGui = Tk()
kiloMent = IntVar()
mileMent = IntVar()
myGui.title("Distance Converter")
myGui.geometry("450x200+500+200")
myLabel = Label(text="Welcome! Please enter your value then choose your option:",fg="blue",justify='center')
myLabel.pack()
kiloEntry = Entry(myGui, textvariable = kiloMent,justify='center').pack()
kilo2milesButton = Button(text = "Kilometers to Miles!", command = kiloFunc).pack()
mileEntry = Entry(myGui, textvariable = mileMent,justify='center').place(x=130,y=105)
miles2kiloButton = Button(text = "Miles to Kilometers!", command = mileFunc).place(x=150,y=135)
reset = Button(text = "Reset Values!", command = main).place(x=10,y=165)
quit = Button(text="Quit", command = closeWin).place(x=385,y=165)
myGui.mainloop()
main()
By calling main() again, you are simply creating another instance of the GUI. What you should do instead is (if I understand correctly), reset the values of the currently existing GUI. You can use the set() method of the GUI objects.
Does
def reset_values():
kiloMent.set(0)
mileMent.set(0)
reset = Button(text="Reset Values!", command=reset_values).place(x=10, y=165)
do the trick?
Looking at your code more thoroughly, however, there are some other problems there, as well. To start with, I would suggest not creating a Label everytime the user tries to convert a value.
This code should work:
from tkinter import *
def main():
def closeWin():
myGui.destroy() # Close Window Function
def kiloFunc():
finalKilo.set(kiloMent.get() * 0.62) # Kilometers to Miles Fuction
def mileFunc():
finalMile.set(mileMent.get() // 0.62) # Miles to Kilometers Function
def clearFunc():
kiloMent.set("0")
mileMent.set("0")
finalKilo.set("")
finalMile.set("")
myGui = Tk()
kiloMent = IntVar()
mileMent = IntVar()
finalKilo = StringVar()
finalMile = StringVar()
myGui.title("Distance Converter")
myGui.geometry("450x200+500+200")
myLabel = Label(text="Welcome! Please enter your value then choose your option:", fg="blue", justify='center')
myLabel.pack()
kiloEntry = Entry(myGui, textvariable=kiloMent, justify='center')
kiloEntry.pack()
kilo2milesButton = Button(text="Kilometers to Miles!", command=kiloFunc)
kilo2milesButton.pack()
mileEntry = Entry(myGui, textvariable=mileMent, justify='center')
mileEntry.place(x=130, y=105)
miles2kiloButton = Button(text="Miles to Kilometers!", command=mileFunc)
miles2kiloButton.place(x=150, y=135)
kiloLabel = Label(textvariable=finalKilo, fg='red', justify='center')
kiloLabel.place(x=200, y=80)
mileLabel = Label(textvariable=finalMile, fg='red', justify='center')
mileLabel.place(x=200, y=170)
reset = Button(text="Reset Values!", command=clearFunc)
reset.place(x=10, y=165)
quit = Button(text="Quit", command=closeWin)
quit.place(x=385, y=165)
myGui.mainloop()
main()
A few notes about your original code besides the ones that Chuck mentioned:
The math and sys imports were unused.
You were setting variables equal to widget.pack() and widget.place(), which are functions that return None.

Python TKInter how do I replace data in my frames?

I'm having a major issue with my code below. So here's what I'm trying to do.
The user enters certain inputs into the entry fields and the program calculates and displays a corresponding image (loaded in the frame champFrame) and it's description (in spellFrame).
What I want is to replace this image and text every time I click on the Calculate! button so that it shows me a new image and new description based on my new inputs.
However, in its current state, when I enter new input and click the Calculate! button, it just adds the new image below the old one and the old one is still there.
How do I change my code around so that I can replace these old values?
I have heard of using the pack_forget() method but it only hides the previous image, does not remove it so I can replace it with a new one.
from Tkinter import *
from PIL import ImageTk
from Calculation import getHighestScore
from ImageHandler import *
import json
import urllib2
top = Tk()
top.title("LOLSpellEfficiency")
top.geometry("600x600")
def loadInputFields(frame):
AP_Label = Label(frame, text="AP")
AD_Label = Label(frame, text="AD")
CDR_Label = Label(frame, text="CDR")
AP_Label.grid(row=0, column=0)
AD_Label.grid(row=1, column=0)
CDR_Label.grid(row=2, column=0)
AP_Entry = Entry(frame)
AD_Entry = Entry(frame)
CDR_Entry = Entry(frame)
AP_Entry.grid(row=0, column=1)
AP_Entry.insert(0, "0")
AD_Entry.grid(row=1, column=1)
AD_Entry.insert(0, "0")
CDR_Entry.grid(row=2, column=1)
CDR_Entry.insert(0, "0")
return [AP_Entry, AD_Entry, CDR_Entry]
def loadButton(frame, entries):
Enter_Button = Button(frame, text="Calculate!", command = lambda: executeProgram(entries))
Enter_Button.pack(side=TOP)
def executeProgram(entries):
AP = float(entries[0].get())
AD = float(entries[1].get())
CDR = float(entries[2].get())
data = getChampionData()
result = getHighestScore(data, AP, AD, CDR)
champPhoto = ImageTk.PhotoImage(getChampionImage(result[0]))
champLabel = Label(championFrame, image=champPhoto)
champLabel.image = champPhoto
champLabel.pack(side = TOP)
champName = Label(championFrame, text = "Champion: " + result[0])
champName.pack(side = BOTTOM)
spellPhoto = ImageTk.PhotoImage(getSpellImage(result[2]))
spellLabel = Label(spellFrame, image=spellPhoto)
spellLabel.image = spellPhoto
spellText = Text(spellFrame, wrap=WORD)
spellText.insert(INSERT, "Spell: " + result[1] + "\n")
spellText.insert(INSERT, "Spell description: " + result[3] + "\n")
spellLabel.pack(side=TOP)
spellText.pack(side=BOTTOM)
championFrame.pack()
spellFrame.pack()
def getChampionData():
URL = "https://global.api.pvp.net/api/lol/static-data/na/v1.2/champion?champData=all&api_key=8e8904b4-c112-4b0f-bd1e-641649d9e569"
return json.load(urllib2.urlopen(URL))
inputFrame = Frame(top)
inputFrame.pack()
buttonFrame = Frame(top)
buttonFrame.pack()
championFrame = Frame(top)
spellFrame = Frame(top)
championFrame.pack()
spellFrame.pack()
entries = loadInputFields(inputFrame)
loadButton(buttonFrame, entries)
top.mainloop()
Do not create widgets inside of executeProgram. Instead, create them in your main application, and simply change the widgets inside executeProgram.
All widgets have a configure method which lets you change all of the attributes of that widget. For example, to change the image on a label you would do something like this:
champPhoto = ImageTk.PhotoImage(getChampionImage(result[0]))
champLabel.configure(image=champPhoto)
champLabel.image = champPhoto

Categories