Pass variables between modules - python

I have a tkinter gui that has a basic entry box and search button. That searches a list in a module named SearchList.py
Main.py
from tkinter import *
from SearchList import *
root = Tk()
Output = []
def search():
search = e.get()
Output= SearchList.go(search)
#search bar
e= Entry(root, width=50, borderwidth=5)
e.grid(row=0, column=0, columnspan=2)
#search button
doneButton = Button(root, text="Search", width= 10, command=search).grid(row=0, column=4)
#arranges output in a 5 column rectangle
r, c = (1,0)
c_limit= 5
for thing in Output:
myButton = Button(root, text=thing,height=5, width=25, borderwidth=3, padx=10).grid(row=r,column=c)
c+=1
if c == c_limit:
c=0
r+=1
root.mainloop()
This lets me input what I want to search and sends it to the Searchlist.py module and the output (matches from list) is arranged in a rectangle.
SearchList.py
Output = []
def main(search):
for x in range(list):
if list[x]== search:
Output.append(list[x])
else:
continue
Output.sort
return Output
def go(search):
with client:
client.loop.run_until_complete(main(search))
But it keeps returning None.
Also I know I must be calling the module incorrectly- just not sure how.

There are two minor issues here. First you are missing a return in SearchList.py:
def go(search):
with client:
# insert return here
return client.loop.run_until_complete(main(search))
Second, you don't write to the correct variable in search:
def search():
# use global keyword to reference global variable Output
global Output
search = e.get()
Output= SearchList.go(search)

Related

Python tkinter how to get value from an entry box

I am trying to make a little thing in python like JOpenframe is java and I'm trying to make an entry box. That works fine but when I try to get the value and assign it to variable "t" nothing works. This is what I have:
def ButtonBox(text):
root = Tk()
root.geometry("300x150")
t = Label(root, text = text, font = ("Times New Roman", 14))
t.pack()
e = Entry(root, borderwidth = 5, width = 50)
e.pack()
def Stop():
root.destroy()
g = e.get()
ok = Button(root, text = "OK", command = Stop)
ok.pack()
root.mainloop()
t = ButtonBox("f")
I've tried to make "g" a global variable but that doesn't work. I have no idea how to get the value from this, and I'm hoping someone who does can help me out. Thanks!
If you want to return the value of the entry box after ButtonBox() exits, you need to:
initialize g inside ButtonBox()
declare g as nonlocal variable inside inner function Stop()
call g = e.get() before destroying the window
Below is the modified code:
from tkinter import *
def ButtonBox(text):
g = "" # initialize g
root = Tk()
root.geometry("300x150")
t = Label(root, text = text, font = ("Times New Roman", 14))
t.pack()
e = Entry(root, borderwidth = 5, width = 50)
e.pack()
def Stop():
# declare g as nonlocal variable
nonlocal g
# get the value of the entry box before destroying window
g = e.get()
root.destroy()
ok = Button(root, text = "OK", command = Stop)
ok.pack()
root.mainloop()
# return the value of the entry box
return g
t = ButtonBox("f")
print(t)

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

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()

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()

Tkinter problem creating button to collect text from user

I am new to Tkinter, and am trying to create a hangman app. I have already created a command-line version, so I thought it would be a nice beginning project. When learning I was told to use window.mainloop() for creating/updating, but my program contains a while loop, and so that hasn't worked. I am not able to type into the textbox i have created at all and when I click the button, it gives me a NameError saying textEntry in my click() method is not defined. Any help or guidance of where else to look would be much appreciated. Thanks! My code is posted below
from tkinter import *
from random import choice
def click():
guess = textEntry.get()
return guess
def main():
input_file = open('hangman_word_list.txt','r')
word_list = input_file.read().split()
window = Tk()
window.title("Play Hangman!")
window.configure(background="black")
p1 = PhotoImage(file='h1.gif')
p2 = PhotoImage(file='h2.gif')
p3 = PhotoImage(file='h3.gif')
p4 = PhotoImage(file='h4.gif')
p5 = PhotoImage(file='h5.gif')
p6 = PhotoImage(file='h6.gif')
Label(window,image=p1,bg="purple").grid(row=0,column=0,columnspan=4)
word = choice(word_list)
correctList = list(word)
lettersLeft = len(word)
hiddenWord = ('*' * lettersLeft)
wrongGuessList = []
lives = 6
again = True
nowPhoto = p1
guess = 'empty'
while lettersLeft > 0 and again == True:
Label(window,text="Your word is "+hiddenWord ,bg="gray",fg="purple",font="none 12 bold").grid(row=1,column=0,sticky=W)
Label(window,text="Enter a letter: " ,bg="gray",fg="purple",font="none 12 bold").grid(row=2,column=0,sticky=W)
textEntry = Entry(window,width=5,bg="white")
textEntry.grid(row=2,column=1,sticky=W)
guess = Button(window,text="Guess",width=5,command=click).grid(row=3,column=2,sticky=W)
window.update()
main()
The mainloop() listens continously for any hook that you have defined, which means you don't have to worry about that. Just define the right hooks, like the button command.
I introduced a nicer way to handle the images by putting them in a list and then reducing the list for each image requested. This makes it easier to update the image.
Then put all processing, like checking if a uessed letter is in the word etc. in the click() function.
from tkinter import *
window = Tk()
# Make a list of all the pictures
pic_list = ['h6.gif','h5.gif','h4.gif','h3.gif','h2.gif','h1.gif']
img = PhotoImage(file=pic_list.pop()) # Get image from list of images
hangman = Label(window, image=img) # Save reference to the Label as
hangman.grid(row=0,column=0,columnspan=4) # you will update it later
# I simplified the word selection a bit
word = 'Wensleydale'
correctList = list(word)
lettersLeft = len(word)
hiddenWord = ('*' * lettersLeft)
wrongGuessList = []
guess = 'empty'
# Build the rest of the GUI
Label(window,text="Your word is " + hiddenWord, bg="gray", fg="purple",
font="none 12 bold").grid(row=1, column=0, sticky=W, columnspan=4)
Label(window,text="Enter a letter: ", bg="gray", fg="purple",
font="none 12 bold").grid(row=2, column=0, sticky=W)
textEntry = Entry(window, width=10, bg="white")
textEntry.grid(row=2, column=1, sticky=W, columnspan=3)
def click(): # Callback function
guess = textEntry.get()
# Put all other processing here.
# Updating the image
img = PhotoImage(file=pic_list.pop()) # Get next image from list
hangman.configure(image=img) # Replace image in label
hangman.image = img # Keep reference to the new image
# Create button and associate it with the command callback function
guess_button = Button(window, text="Guess", width=5,
command=click).grid(row=3, column=2, sticky=W)
window.mainloop() # Will loop continously listening for buttonpress
Firstly, a while loop is not recommended for use when it comes to using tkinter module as the window would be running on the main thread. Logically, when using buttons, you can use if statements so that it won't trigger a specific part of code until lettersLeft > 0 and again == True. And the use of variable textEntry in a function is obviously not available to Python because there is no declaration of it. So you either pass the variable as argument or declare a global variable.
Here is what I would think of:
from tkinter import *
from random import choice
def get_wordlist():
return open("Hangman word list.txt", 'r').read().split("split by something here.")
class Hangman(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master.title("Hangman")
self.master.configure(bg="black")
self.wordlist = get_wordlist()
self.p1 = PhotoImage(file="h1.gif")
self.word = choice(self.wordlist)
self.hidden_word = list("".join("_" for x in word))
self.wrong_guess = []
self.lives = 6
self.word_display = Label(window, text=str(*(hidden for hidden in hidden_word)), image=p1, bg="purple", fg="white")
self.word_display.grid(row=0, column=0, columnspan=4)
Label(window, text="Enter a letter: ", bg="gray", fg="purple", font="none 12 bold").grid(row=2, column=0, sticky=W)
self.entry = Entry(window, width=5, bg="white")
self.entry.grid(row=2, column=1, sticky="W")
self.guess = Button(window, text="Guess", command=lambda: button_action(self))
self.guess.grid()
self.again = False
def button_action(self):
user_input = self.entry.get()
if len(user_input) == len(word):
for i in range(len(word)):
if word[i] == user_input[i]:
self.hidden_word[i] = word[i]
if "_" not in self.hidden_word:
self.word_display.config(text="You won! The correct word was: " + self.word)
self.after(3000, self.quit())
else:
self.word_display.config(text="Guess not correct! " + str(*(hidden for hidden in hidden_word)))
self.lives -= 1
else:
self.word_display.config(text="Guess not correct! " + str(*(hidden for hidden in hidden_word)))
self.lives -= 1
if self.lives <= 0:
self.word_display.config(text="You lost! The correct word was: " + self.word)
self.master.after(3000, self.quit())
Please note 2 things:
Try not to create redundant variables
Before even asking a question, please do look on python tkinter docs.

Make a dictionary using tkinter, GUI

I want to make a dictionary by using a GUI, I was thinking of making two entries, one for the object and the other for the key. And I want to make a button that execute the information and add it to the empty dictionary.
from tkinter import *
fL = {}
def commando(fL):
fL.update({x:int(y)})
root = Tk()
root.title("Spam Words")
label_1 = Label(root, text="Say a word: ", bg="#333333", fg="white")
label_2 = Label(root, text="Give it a value, 1-10:", bg="#333333", fg="white")
entry_1 = Entry(root, textvariable=x)
entry_2 = Entry(root, textvariable=y)
label_1.grid(row=1)
label_2.grid(row=3)
entry_1.grid(row=2, column=0)
entry_2.grid(row=4, column=0)
but = Button(root, text="Execute", bg="#333333", fg="white", command=commando)
but.grid(row=5, column=0)
root.mainloop()
I want to use that dictionary later in my main program. You see if it would be a function, I would just go in IDLE and do..
def forbiddenOrd():
fL = {}
uppdate = True
while uppdate:
x = input('Object')
y = input('Key')
if x == 'Klar':
break
else:
fL.update({x:int(y)})
return fL
And then just use the function further on in my program
Any suggestions?
I appreciate it. Thank you
You are close to achieving what you want. There are a few modifications that need to be made. First, lets start with the entry boxes entry_1 and entry_2. Using a text variable like you did is a good approach; however I did not see them defined, so here they are:
x = StringVar()
y = StringVar()
Next, we need to change how you call the commando function and what parameters you pass though it. I want to pass the x and y values though, but I can't do this by just using something like command=commando(x.get(), y.get()), I need to use lambda as follows:
but = Button(root, text="Execute", bg="#333333", fg="white", command=lambda :commando(x.get(), y.get()))
Now why did I pass the values x and y as x.get() and y.get()? In order to get the values from a tkinter variable such as x and y, we need to use .get().
Finally, let's fix the commando function. You cannot use it as you did with fL being the parameter. This is because any parameter you set there becomes a private variable to that function even if it appears elsewhere in you code. In other words, defining a function as def commando(fL): will prevent the fL dictionary outside the function from being assessed within commando. How do you fix this? Use different parameters. Since we are passing x and y into the function, let's use those as parameter names. This is how our function looks now:
def commando(x, y):
fL.update({x:int(y)})
This will create new items in your dictionary. Here is the completed code:
from tkinter import *
fL = {}
def commando(x, y):
fL.update({x:int(y)}) # Please note that these x and y vars are private to this function. They are not the x and y vars as defined below.
print(fL)
root = Tk()
root.title("Spam Words")
x = StringVar() # Creating the variables that will get the user's input.
y = StringVar()
label_1 = Label(root, text="Say a word: ", bg="#333333", fg="white")
label_2 = Label(root, text="Give it a value, 1-10:", bg="#333333", fg="white")
entry_1 = Entry(root, textvariable=x)
entry_2 = Entry(root, textvariable=y)
label_1.grid(row=1)
label_2.grid(row=3)
entry_1.grid(row=2, column=0)
entry_2.grid(row=4, column=0)
but = Button(root, text="Execute", bg="#333333", fg="white", command=lambda :commando(x.get(), y.get())) # Note the use of lambda and the x and y variables.
but.grid(row=5, column=0)
root.mainloop()

Categories