Update turtle/gui while waiting for input python - python

I'm making a chat program, but I have run across a problem: the screen only updates after input. I'm using turtle to show the chat (I know, turtle isn't really that good for this purpose, but it's very simple.)
This is the code in my loop:
while True:
ind = userlist.index(user)
if statlist[ind] == 'banned':
print('You have been banned.')
break
word = input('>>> ')
command(word)
if word != '':
chat = user + '(' + status + '): ' + word
update_room(chat)
refresh()
Pretty much everything can be ignored here, except the
word = input('>>> ')
and
refresh()
The refresh() is what updates the turtle room.
How could I make it so that it would print out new chat, even as the user is typing? Would 2 side-by-side while loops work?
I acknowledge that my program isn't that well organized and that to fix this I will probably have to rewrite this loop.
Note: I'd rather not import anything, but if an import is needed then it would be great if that module came preloaded with python.
Or another question: Is it possible to have 2 infinite while loops running side by side at the same time?

So I'm pretty new at python but I have an idea that will just be extremely repetitive. You need to first remove the input part and make a ton of functions like this:
def key_a:
global key_in
key_in = key_in + 'a'
def key_b:
global key_in
key_in = key_in + 'b'
def key_c:
global key_in
key_in = key_in + 'c'
Have it so if your input is enter, then it will set it to the word and reset the input variable.
def key_enter:
global key_in
global word
word = key_in
key_in = ''
Then bind your inputs (think of "win" as your window variable.)
win.listen()
win.onkeypress(key_a, 'a')
Also do the same for capital letters.
win.onkeypress(caps_key_a, 'A')
Please tell me if this helps.

Here's an improvement on TaCo's answer suggesting onkeypress which enables real-time typed user input so you can re-render even if the user is holding down keys.
My contribution is to use a loop that calls a general function so there's no need to manually create a separate function per key. I've also provided a minimal, runnable example which should be easily adaptable to a chat interface, typing game or other context.
I haven't attempted to handle every key and edge case, so you might want to dig into the list of Tk keys and make sure it works for your needs. Feel free to suggest an improvement if you encounter any odd behavior.
import turtle
from datetime import datetime
def tick():
current_time = datetime.now().strftime("%H:%M:%S")
turtle.clear()
turtle.goto(0, 50)
turtle.write(current_time, align="center", font=font)
turtle.goto(0, -50)
turtle.write(f"'{text}'", align="center", font=font)
turtle.update()
turtle.Screen().ontimer(tick, 1000 // 30)
def handle_keypress(key):
global text
text += key
def handle_backspace():
global text
text = text[:-1]
def add_key_handler(key):
turtle.Screen().onkeypress(lambda: handle_keypress(key), key)
font = "Courier New", 18, "normal"
text = ""
turtle.tracer(0)
turtle.penup()
turtle.hideturtle()
for i in range(33, 122):
if i != 45:
add_key_handler(chr(i))
turtle.Screen().onkeypress(handle_backspace, "BackSpace")
turtle.Screen().onkeypress(lambda: handle_keypress(" "), "space")
turtle.Screen().onkeypress(lambda: handle_keypress("-"), "minus")
turtle.listen()
tick()
turtle.exitonclick()
Reference: Is there a complete list of key event names used by turtle-graphics?

Related

How to go through while loop again?

Im making a simple question and answer app in python , in this specific example it displays a word in simple chinese and gives two answers to pick wrong or right , i'm struggling to present a new question without restarting my code. This my go at making an app that helps me learn chinese and I wanted to use minimum help , hence the weird code.
For example :
the question is what is 1+1 and the user answered two then I want to go thourgh the code again an present the next question.
the specific section im trying the run from inside a function, so when the user answers correctly or incorrectly by pressing the button in the function I want to go through the code again and present my next question
`
# ans
def button_1(event):
if Ans_option1.text == ans_or_not["ans"]:
print('correct')
return 'correct'
else:
print("incorrect")
def button_2 (event):
if Ans_option2.text == ans_or_not["ans"]:
print('correct')
return 'correct'
else:
print("incorrect")
Ans_option1 = gp.Button(app,return_1(), button_1)
Ans_option2 = gp.Button(app,return_2(),button_2)
app.add(Ans_option1,3,2, align = 'center')
app.add(Ans_option2,3,4, align = 'center')
app.run()
`
whole code
import gooeypie as gp
import random
app = gp.GooeyPieApp ('hello')
app.set_size (1000,500)
i = 2
n =3
while True :
# use dictionary instead of lists so we c an have an answer to the questions
question_dict = {
'xihuan' : 'like',
'Wo': 'I',
'Ni': 'you'
}
# random picks a value from a list of values made here
picker = random.choice(list(question_dict.values()))
# I remake the same list here again as the indexing stays the same then find the index for the random value
ind = list(question_dict.values()).index(picker)
# I make a list of the keys and they have mathing indexes to their values and we use the index number given to us previously to find the key
final = list(question_dict.keys())[ind]
# print(final)
test = 1
def question ():
question_dict.pop(final)
print(question_dict)
# return final
return final
ans_or_not = {
# this works first before the item is popped so it can cause a they same two words to appear on the buttons
# varialbe from inside the functions arent stected outside , making this whole dictionary meaningless
'ans' : picker,
'non' : random.choice(list(question_dict.values()))
}
print(ans_or_not["non"])
print(ans_or_not["ans"])
while ans_or_not["non"] == ans_or_not["ans"]:
ans_or_not.pop('non')
print(ans_or_not)
ans_or_not['non'] = random.choice(list(question_dict.values()))
print(ans_or_not["non"])
print(ans_or_not["ans"])
nums = random.randrange(1,3)
print(nums)
def return_1():
# while anss == nons :
# anss = random.randrange(0,2)
# print(anss + ','+ nons)
if nums == 1 :
return ans_or_not["ans"]
if nums == 2:
return ans_or_not["non"]
def return_2():
# while anss == nons :
# anss = random.randrange(0,2)
# print(anss + ','+ nons)
if nums == 1 :
return ans_or_not["non"]
elif nums == 2:
return ans_or_not["ans"]
# design and layout
def menu_select (event):
pass
menu_path = ' > '.join(event.menu)
status.text = menu_path
app.add_menu_item('Menu 1', 'Item 1', menu_select)
# grid setup
app.set_grid(4,5)
question_lbl = gp.Label(app,question())
app.add(question_lbl,2,3, align = 'center')
# ans
def button_1(event):
if Ans_option1.text == ans_or_not["ans"]:
print('correct')
return 'correct'
else:
print("incorrect")
def button_2 (event):
if Ans_option2.text == ans_or_not["ans"]:
print('correct')
return 'correct'
else:
print("incorrect")
Ans_option1 = gp.Button(app,return_1(), button_1)
Ans_option2 = gp.Button(app,return_2(),button_2)
app.add(Ans_option1,3,2, align = 'center')
app.add(Ans_option2,3,4, align = 'center')
app.run()
What i've tried
i've tried using the continue function
ways to restart while loops
You have the problem wrong.
This is going to sound really complicated, but stay with me. So what app.run() does is start the program, and it displays what you have already added to it. By putting app.run() in the while loop, despite calling it multiple times, will only call once. What you need to do is draw the label and buttons, run the app, then start the while loop. In fact, I wouldn't use a while loop here at all. Instead, I would have is so you have a dictionary for the right and wrong answers, then simply modify that and the button text when you get the answer correct. I don't really understand your code, but it would look something like:
#function for choosing answer
#function for checking button one
#function for checking button two
#draw button one and two and label
app.run()
Also, you would have it so that if you got the answer right, you would choose a new one.

How do I Run a Background Timer for Each Prompt in My Word Game?

I'm making an unoriginal game for a first project that just runs in my python terminal. The user is randomly given a set of 2-3 letters and the user has to come up with a real word (checked by the Webster dictionary) that contains the given set of letters within 5 seconds. For example, if the game generates "le" the user can input "elephant" within 5 seconds as a correct word and gives them a point.
The problem is that I can't seem to implement the 5 second timer function to run in the back for every time a prompt is given without messing up some other part or running into another problem. I've looked into threading and can't seem to make use of it.
Here is the code for the main game:
from letters import letter_sets_list
fhand = open("words_dictionary.json")
data = fhand.read()
global score
score = int(0)
game_over = False
while game_over is False:
import random
random_letters = random.choice(letter_sets_list)
print('Word that contains:', random_letters)
answer = input("Type a word:")
if answer in data and random_letters in answer:
score += 1
print("nice one")
else:
game_over = True
print("Game Over \n Score:", score)
fhand.close()
exit()
Here is the timer function I found off YouTube and tried to implement:
def countdown():
global my_timer
my_timer = int(5)
for x in range(5):
my_timer -= 1
sleep(1)
countdown_thread = threading.Thread(target=countdown)
countdown_thread.start()
Take a look at that. Especially check if that will work for you:
import time
from threading import Thread
answer = None
def check():
time.sleep(2)
if answer != None:
return
print("Too Slow")
Thread(target = check).start()
answer = input("Input something: ")
Edit: I tried to implement code from my previous answer to your code but with a little different approach:
import time, threading
#from letters import letter_sets_list
#import random
#fhand = open("words_dictionary.json")
#data = fhand.read()
data = ["answer"]
answer = [None]
random_letters = [None]
global score
score = int(0)
game_over = False
x = 0
def game(answer, random_letters):
#random_letters = random.choice(letter_sets_list)
print('Word that contains:', random_letters)
while True:
answer[0] = input("Type a word: ")
mythread = threading.Thread(target=game, args=(answer, random_letters))
mythread.daemon = True
mythread.start()
for increment in range(5):
time.sleep(1)
if answer[0] in data: # and random_letters in answer
score += 1
print("Good answer")
x = 1
break
if x != 1:
print("\nTime is up")
else:
x = 0
game_over = True
In this approach I didnt use time.sleep() inside threaded function but outside of it which helps with killing it. Also i assumed that if your answer is incorrect you would like to have another chance to answer untill time is up or answer is correct so I just used while loop in threaded function. The code is quite simple so I think if you spend a little time analysing your parts of the code you will figure it out.
Some parts of the code I didn't use as I dont have access to your json files ect., but if I understand correctly what you're trying to do, it shoud work. Also check how will behave your kernel. In my case sometimes it shows some problems but my PC is not the best and so it might be only problem with RAM or other part of my computer as it happens quite often with my projects.

Cannot figure out how to finish hangman date signing

display a double 3 time method for tracking analysis with frameworks
we need to find the x for y
and describe why it happeneds that way
do not quote for 32 x 8. Most of the If the player guess a letter which exists in the word, the script writes it in all its correct positions. The player has 10 turns to guess the word. You can easily customize the game by changing the variables.live coding demo portion of the course and showing the process of coding a
#importing the time module
import time
#welcoming the user
name = raw_input("What is your name? ")
print "Hello, " + name, "Time to play hangman!"
print "
"
#wait for 1 second
time.sleep(1)
print "Start guessing..."
time.sleep(0.5)
#here we set the secret
word = "secret"
#creates an variable with an empty value
guesses = ''
#determine the number of turns
turns = 10
# Create a while loop
#check if the turns are more than zero
while turns > 0:
# make a counter that starts with zero
failed = 0
# for every character in secret_word
for char in word:
# see if the character is in the players guess
if char in guesses:
# print then out the character
print char,
else:
# if not found, print a dash
print "_",
# and increase the failed counter with one
failed += 1
# if failed is equal to zero
# print You Won
if failed == 0:
print "
You won"
# exit the script
break
print
# ask the user go guess a character
guess = raw_input("guess a character:")
# set the players guess to guesses
guesses += guess
# if the guess is not found in the secret word
if guess not in word:
# turns counter decreases with 1 (now 9)
turns -= 1
# print wrong
print "Wrong
"
# how many turns are left
print "You have", + turns, 'more guesses'
# if the turns are equal to zero
if turns == 0:
# print "You Lose"
print "You Lose
"
The mainloop is a function of the root window, so you should assign a name to it:
if __name__ == '__main__':
url = 'https://api.exchangerate-api.com/v4/latest/USD'
converter = MikesMagicalConverter(url)
app = App(converter) # Assing a name to root window
app.mainloop() # Run root window mainloop
When you create the button you should provide a reference to the master:
buttonExample = tk.Button(self, # Provide reference to master
text="Create new window",
command=lambda:self.currency_converter.createNewWindow(self)) # Pass reference
buttonExample.pack()
The command argument is a bit trickier; the class MikesMagicalConverter is not a widget and does not inherit from tkiner so you'll have to pass a reference to use as master to the Toplevel window.
You must provide a self parameter to the createNewWindow() method.
def createNewWindow(self, master):
newWindow = tk.Toplevel(master) # Using reference as master
labelExample = tk.Label(newWindow, text = "New Window")
buttonExample = tk.Button(newWindow, text = "New Window button")
labelExample.pack()
buttonExample.pack()
In general: many of your lines are way to long, makes the code hard to read.
With those changes the code will still generate error, but the button and Toplevel window pops up. I'm thinking you might rather separate the currency calculations from the GUI code.

How do you update a variable when using a button in tkinter?

I am writing a simple game where when the 'calculate' button is clicked, it performs the necessary calculations and displays a messagebox to the user. The user can then keep playing. However, the variable that keeps track of the money the user has, 'starting', does not update each time the button is clicked and it uses the starting value of 1000. How can I have it update? Thank you!
starting = 1000
#calculation procedure
def calculate(starting):
dice1 = random.randrange(1,7)
get_bet_entry=float(bet_entry.get())
get_roll_entry = float(roll_entry.get())
if dice1 == get_roll_entry:
starting = starting + get_bet_entry
messagebox.showinfo("Answer","You won! Your new total is $" + str(starting))
return(starting)
else:
starting = starting - get_bet_entry
messagebox.showinfo("Answer","You are wrong, the number was " + str(dice1) + '. You have $' + str(starting))
return(starting)
#designing bet button
B2 = Button(root,text = "Bet", padx=50, command = lambda: calculate(starting))
You can declare starting as a global variable inside your calculate function, so it gets updated in the global scope.
You could also make "starting" part of a mutable object if you want to avoid globals.
You shouldn't return a value from button's callback since it doesn't have a variable to return.
You can either use global to update your variable within a method or use IntVar(). I would suggest using IntVar().
starting = IntVar(root)
starting.set(1000)
def calculate():
#calculations
starting.set(calculation_result)
messagebox.showinfo("Answer","You won! Your new total is $" + str(starting.get()))
B2 = Button(......, command = calculate)
If you really want to use global,
starting = 1000
def calculate():
global starting
#calculations
starting = calculation_result
B2 = Button(......, command = calculate)
Note that in both approaches, you don't need to pass starting as parameter to your method.

Command function for button "resets"

So in my tkinter python program I am calling on a command when a button is clicked. When that happens it runs a function but in the function I have it set a label to something on the first time the button is clicked and after that it should only update the said label. Basically after the attempt it changes the attempt to 1 ensuring the if statement will see that and not allow it to pass. However it keeps resetting and I don't know how to stop it. When you click the button no matter first or third the button resets and proof of that occurs because the h gets printed. It's as if the function restarts but it shouldn't since it's a loop for the GUI.
def fight(): #Sees which one is stronger if user is stronger he gets win if no he gets loss also displays enemy stats and removes used characters after round is finished
try:
attempt=0
namel = ""
namer=""
left = lbox.curselection()[0]
right = rbox.curselection()[0]
totalleft = 0
totalright = 0
if left == 0:
namel = "Rash"
totalleft = Rash.total
elif left==1:
namel = "Untss"
totalleft = Untss.total
elif left==2:
namel = "Illora"
totalleft = 60+35+80
if right == 0:
namer = "Zys"
totalright = Zys.total
elif right==1:
namer = "Eentha"
totalright = Eentha.total
elif right==2:
namer = "Dant"
totalright = Dant.total
lbox.delete(lbox.curselection()[0])
rbox.delete(rbox.curselection()[0])
print(namel)
print(namer)
if attempt == 0:
wins.set("Wins")
loss.set("Loss")
print("h")
attempt=1
if (totalleft>totalright):
wins.set(wins.get()+"\n"+namel)
loss.set(loss.get()+"\n"+namer)
else:
wins.set(wins.get()+"\n"+namer)
loss.set(loss.get()+"\n"+namel)
except IndexError:
pass
Also for those of you who saw my previous question I still need help with that I just also want to fix this bug too.
At beginning of function fight you set attempt = 0 so you reset it.
Besides attempt is local variable. It is created when you execute function fight and it is deleted when you leave function fight. You have to use global variable (or global IntVar)
attempt = 0
def fight():
global attempt
BTW: of you use only values 0/1 in attempt then you can use True/False.
attempt = False
def fight():
global attempt
...
if not attempt:
attempt = True

Categories