binding return key in Python GUI - python

Working on a number guessing assignment for an informatics course and cannot for the life of me on this program bind this key. Using previous programs and class example I am able to bind this key to perform certain functions however not in this particular one. Therefore, I am assuming there is something super small wrong and im just overlooking it. Any help is appreciated.
from tkinter import *
import random
class Application(Frame):
def __init__(self, master): #sets up gui elements
Frame.__init__(self, master)
self.grid()
self.create_widgets()
self.number = random.randint(0, 9)
def create_widgets(self):
# creates instructions
Label(self, text = "I'm thinking of a number between 0 and 9.").grid(row = 0, column = 0, sticky = W)
Label(self, text = "Try and guess it!").grid(row = 1, column = 0, sticky = W)
# create guess label and entry
Label(self, text = "Your guess:").grid(row = 2, column = 0, sticky = W)
self.guess_ent = Entry(self)
self.guess_ent.grid(row = 2, column = 1, sticky = W)
# creates button to initiate run function
self.bttn=Button(self, text = "Submit", command = self.run)
self.bttn.grid(row = 3, column = 1, sticky = W)
#binds return key
self.bttn.bind('<KeyPress>', self.enter)
self.bttn.focus_set()
# creates feedback text box for run function
self.text = Text(self, width = 75, height = 10, wrap = WORD)
self.text.grid(row = 4, column = 0, columnspan = 4)
def run(self):
#gets random number
guess = int(self.guess_ent.get())
#if to test guesses and give appropriate feedback
if guess != self.number:
print_text = "You guessed {0}.".format(guess)
if guess > self.number:
print_text += " That's too high. Guess lower..."
elif guess < self.number:
print_text += " That's too low. Guess higher..."
self.text.delete(0.0, END)
self.text.insert(0.0, print_text)
self.guess_ent.delete(0, END)
else:
print_text = "That's the right number! You did it!!"
self.text.delete(0.0, END)
self.text.insert(0.0, print_text)
def enter(self, event):
if event.keysym == "Return":
self.run()
# main
root = Tk()
root.title("Number Guesser")
app = Application(root)
root.mainloop()

The return key in tkinter is also Return, hence your code should be :
self.bttn.bind('<Return>', self.enter)
You are binding the key to a button which does not get focus until pressed or tabbed into, making it almost impossible to notice the trigger of the binding, because your button and the bind call the same method.
Bind to the Entry widget such that you can trigger the binding while in the widget:
self.guess_ent.bind('<Return>', self.enter)

Related

Whats wrong with this GUI program? - it says 'tra' is not defined

im a beginner programer and made this GUI ceasar code encrypter. I based it on a normal python program i made earlier, and i think i changed sufficiently, but evidently i didnt as it doesnt work. It tells me that the variable 'tra' is not defined.
The program:
from tkinter import *
class Application(Frame):
def __init__(self, master):
super(Application, self).__init__(master)
self.grid()
self.createwidgets()
def createwidgets(self):
Label(self,
text = "Encrypt a message:",
).grid(row = 0, column = 0, columnspan = 2, sticky = W)
Label(self,
text = "Whats your message?:",
).grid(row = 1, column = 0, sticky = W)
self.messageent = Entry(self)
self.messageent.grid(row = 3, column = 0, sticky = W)
Label(self,
text = "Whats the key?:(1 - 25)",
).grid(row = 4, column = 0, sticky = W)
self.keyent = Entry(self)
self.keyent.grid(row = 5, column = 0, sticky = W)
Button(self,
text = "Click for coded message",
command = self.encrypt
).grid(row = 6, column = 0, sticky = W)
self.messagetxt = Text(self, width = 75, height = 10, wrap = WORD)
self.messagetxt.grid(row = 7, column = 0, columnspan = 4)
def things():
message = self.messageent.get()
key = self.keyent.get()
def getTranslatedMessage(message, key):
tra = ''
for symbol in message:
if symbol.isalpha():
num = ord(symbol)
num += key
if symbol.isupper():
if num > ord('Z'):
num -= 26
elif num < ord('A'):
num += 26
elif symbol.islower():
if num > ord('z'):
num -= 26
elif num < ord('a'):
num += 26
tra += chr(num)
else:
tra += symbol
def encrypt(self):
encryptedmessage = tra
self.messagetxt.delete(0.0, END)
self.messagetxt.insert(0.0, encryptedmessage)
root = Tk()
root.title("Encrypting message")
app = Application(root)
root.mainloop()
please could tell me whats wrong in this program and how to fix it?
By the way, i am only 12, and i am actually doing programming as a hobby. So i am planning to get better - i made a version of this code in normal(not GUI) python on my own and it worked - want to challenge myself and try to make it work in GUI.
Thank you
I copy/pasted your code and tried to compile it. That resulted in a large number of errors -- even after fixing the initial indentation errors. The main problem is that the variable tra is defined in function getTranslatedMessage() but you try to use it in encrypt(). It seems like you intended for both of those functions to be methods of the Application class; or something similar. Providing a good answer is difficult because your question has a large number of problems. So much so that I am inclined to suggest you do something else with your life than programming.

Why is my function not affecting a button in tkinter?

I'm trying to make Tic Tac Toe in python using tkinter, but I'm running into an issue. I'm trying to make it so when you click on one of the squares, it displays whichever player's symbol on that square. However, with my current function playerCheck, nothing happens when I press them. I can't figure out why this is happening, so I would appreciate any help.
Keep in mind I am in no way finished.
import tkinter as tk
Player1 = "X"
Player2 = "O"
turn = None
playerNumber = None
def playerCheck(function):
if turn == Player1:
playerNumber = Player1
function("white", playerNumber)
elif turn == Player2:
playerNumber = Player2
function("white", playerNumber)
def topLeft(color, player):
topL = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(topL)).grid(row=0,column=0)
def topMiddle(color, player):
topM = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(topMiddle)).grid(row=0,column=1)
def topRight(color, player):
topR = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(topRight)).grid(row=0,column=2)
def middleLeft(color, player):
midL = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(middleLeft)).grid(row=1,column=0)
def middleMiddle(color, player):
midM = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(middleMiddle)).grid(row=1,column=1)
def middleRight(color, player):
midR = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(middleRight)).grid(row=1,column=2)
def bottomLeft(color, player):
botL = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(bottomLeft)).grid(row=2,column=0)
def bottomMiddle(color, player):
botM = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(bottomMiddle)).grid(row=2,column=1)
def bottomRight(color, player):
botR = tk.Button(text=player, fg="black", bg=color, height=5, width=10, command=lambda: playerCheck(bottomRight)).grid(row=2,column=2)
def gameStart():
topLeft("white", "")
topMiddle("white", "")
topRight("white", "")
middleLeft("white", "")
middleMiddle("white", "")
middleRight("white", "")
bottomLeft("white", "")
bottomMiddle("white", "")
bottomRight("white", "")
turn = Player1
def Main():
a = tk.Tk()
a.title("Tick Tack Toe")
a.geometry("250x250")
gameStart()
a.mainloop()
Main()
The argument to playerCheck() is a button, not a function. You should change the button's text and color, not try to call it.
def playerCheck(button):
global turn
button['text'] = turn
button['fg'] = "white"
if turn == Player1:
turn = Player2
else:
turn = Player1
Here is an example of a completely working tic-tac-toe made with tkinter. I used your Button approach. If you are going to make anything with tkinter it should look a lot more like the below code. I commented it all over the place to give you a bit of a guide to what everything is doing, but I did not dumb down the code. Some parts may be very hard for you to understand (like the logic in win_or_block()). That's a good thing. It will force you to research and get better.
tips:
Learn how to create and use classes, so you can separate and organize your code into meaningful chunks.
Your approach is to manually define each individual thing, even if they are the exact same thing. You should consider a more dynamic approach where you create something once and let a loop create and position a bunch of copies/instances of it.
If your code was written properly, according to the design that you laid out, you would technically have a Button that recreates itself when it is clicked. This type of circular logic is bad.
Worry less about Buttons and more about game logic. Your graphics should simply express a condition. You're on your way to making the graphics serve as the logic behind your conditions, and that is a terrible approach.
#python 3.8+
from tkinter import Tk, Frame, Button, Entry, StringVar, IntVar, Checkbutton
from statistics import mean
from random import choice
class Splash(Frame):
WIDTH = 300
HEIGHT = 190
def __init__(self, master, callback, *args, **kwargs):
Frame.__init__(self, master, *args, **kwargs)
self.callback = callback
self.message = StringVar()
self.tricky = IntVar()
#just to make some lines shorter
e = dict(font='calibri 18 bold', bg=self['bg'], border=0, justify='center', textvariable=self.message)
b = dict(font='calibri 18 bold', bg='black', fg='white')
c = dict(font='calibri 16 bold', bg=self['bg'])
Entry(self, **e).place(width=280, height=40, x=10, y=5)
Checkbutton(self, text="tricky", variable=self.tricky, **c).place(width=200, height=30, x=50, y=50)
Button(self, text='1 Player' , command=lambda: self.remove(True) , **b).place(width=200, height=45, x=50, y=90)
Button(self, text='2 Players', command=lambda: self.remove(False), **b).place(width=200, height=45, x=50, y=140)
def remove(self, auto):
self.place_forget()
self.callback(auto)
class Board(Frame):
#if you change this you need to change the font size in self.default_cell and vise-versa
WIDTH = 450
HEIGHT = 393
def __init__(self, master, callback, *args, **kwargs):
Frame.__init__(self, master, *args, **kwargs)
#cell default properties
self.default_cell = dict(
foreground = 'black',
background = 'black',
activebackground = 'black',
disabledforeground = 'black',
text = "",
font = "consolas 48 bold",
relief = 'sunken',
state = 'normal',
width = 4,
height = 1,
)
#make board
for i in range(9):
cell = Button(self, **self.default_cell)
cell.config(command=lambda c=cell, i=i: callback(c, i))
cell.grid(row=int(i//3), column=i%3, sticky='nswe')
def reset(self):
for cell in self.winfo_children():
cell.config(**self.default_cell)
#used to stop cell clicks while splash screen is visible
def lock(self):
for cell in self.winfo_children():
cell.config(state='disabled')
class Game(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
#current player
self.player = 0
#True: against computer - False: against 2nd human
self.auto = False
#stores moves
self.moves = [0]*9
#player colors
self.color = ['red', 'green']
# [crossed swords, flag outline]
self.marks = [chr(9876), chr(9872)]
#positions
self.edge = {1, 7, 3, 5}
self.corner = {0, 6, 2, 8}
#True = hard | False = easy
self.tricky = True
'''
numbers that can't average together with 0 to equal each other
where [n, n, n] is any given winning combination in tic-tac-toe
consider the mean of: [1, 2, 0] vs [1, 1, 1]
against the mean of: [1, 4, 0] vs [1, 1, 1]
'''
self.pids = [1, 4]
#init board
self.board = Board(self, self.move)
self.board.grid(row=0, column=0, sticky='nswe')
#init "game over" screen and place() properties
self.splash = Splash(self, callback=self.reset, bg='gray92')
self.splashprops = dict(
x = (Board.WIDTH-Splash.WIDTH)/2,
y = (Board.HEIGHT-Splash.HEIGHT)/2,
width = Splash.WIDTH,
height = Splash.HEIGHT
)
self.show_splash("Connect 3 And Conquer")
'''
This method is tricky. It is used to check:
1: if the current player has won (id=current_id, n=4)
2: if the computer can win (id=player2_id, n=3)
3: if the computer can block a win (id=player1_id, n=3)
'''
def win_or_block(self, id, n=3):
best = -1
try:
for a in range(3):
#vertical
m = self.moves[a::3]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = (m.index(0) * 3) + a
break
#horizontal
m = self.moves[a*3:a*3+3]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = m.index(0) + (a * 3)
break
#back slash
if best < 0:
m = self.moves[0::4]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = m.index(0) * 4
#forward slash
if best < 0:
m = self.moves[2::2][0:3]
l = list(filter(lambda i: i>0, m))+[id]
if len(l) == n and mean(l) == id:
best = (m.index(0) + 1) * 2
except ValueError:
#m.index(0) does not exist, current player has won
best = 0
return best
def best(self, index):
best = -1
#computer checks if it can win, and if not, then if it can block
for i in range(1, -1, -1):
best = self.win_or_block(self.pids[i])
if best > -1:
break
#if the computer cannot win or there is nothing to block
if best < 0:
avail = {i for i, v in enumerate(self.moves) if v == 0}
c = list(self.corner.intersection(avail)) #corners
e = list(self.edge.intersection(avail)) #edges
#choose the middle or mirror opposite of the last move
if self.tricky:
b = 4 if 4 in avail else abs(index - 8)
if b in avail:
best = b
#attempt a random choice in this order: corner, center, edge
if best < 0:
if len(c):
best = choice(c)
elif 4 in avail:
best = 4
else:
best = choice(e)
return best
def move(self, button, index):
#mark the square
button.config(bg=self.color[self.player], text=self.marks[self.player], state='disabled')
#record the move
self.moves[index] = self.pids[self.player]
#game over screens
if self.win_or_block(self.pids[self.player], 4) > -1: #check win
self.show_splash(f'Player {self.player+1} Has Conquered!')
return
elif self.moves.count(0) == 0: #check "no more moves"
self.show_splash('Stalemate!')
return
#derive next player ~ Player1 = 0, Player2 = 1
self.player = (self.player + 1)%2
if self.auto and self.player == 1:
#invoke the button with the child index that corresponds to the "best" move
self.board.winfo_children()[self.best(index)].invoke()
def show_splash(self, msg):
self.board.lock()
self.splash.message.set(msg)
self.splash.place(**self.splashprops)
def reset(self, auto):
self.tricky = bool(self.splash.tricky.get())
self.auto = auto
self.player = 0
self.moves = [0]*9
self.board.reset()
if __name__ == '__main__':
app = Game()
app.title("Connect 3 And Conquer")
#lock down the window size
app.minsize(Board.WIDTH, Board.HEIGHT)
app.maxsize(Board.WIDTH, Board.HEIGHT)
app.mainloop()
aside:
I understand you are new. Don't take my criticisms to heart. The point is to make you better. Anybody could come in here and tell you how to make poor code work. My agenda is to stop you from writing poor code in the first place - by giving you an excellent example and explaining where you went wrong.
Cheers

How to save counter of entries in str and show it in Text field?

Using such example i want to count number of entries. And represent string with number of entries in Text field. Like, for example:
1: number of entries(1)
21: number of entries(2)
...
Where should i put my counter variable?
import random
from tkinter import *
class MyApp(Frame):
def __init__(self, master):
super(MyApp, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
Label(self, text = 'Your number:').grid(row = 0, column = 0, sticky = W)
self.num_ent = Entry(self)
self.num_ent.grid(row = 0, column = 1, sticky = W)
Button(self, text = 'Check', command = self.update).grid(row = 0, column = 2, sticky = W)
self.user_text = Text(self, width = 50, height = 40, wrap = WORD)
self.user_text.grid(row = 2, column = 0, columnspan = 3)
def update(self):
guess = self.num_ent.get()
guess += '\n'
self.user_text.insert(0.0, guess)
root = Tk()
root.geometry('410x200')
root.title('Entries counter')
app = MyApp(root)
root.mainloop()
If I understand what you want correctly, simply keep count of the number of button presses, you can define a count variable in __init__ like
self.count = 0
And increase and print it in update like
def update(self):
self.count += 1
guess = self.num_ent.get()
guess += '\n'
self.user_text.insert(0.0, 'Guess #{}: {}'.format(self.count, guess))
It seems you're using Python 3.
The easiest way to store your counter is to use a dictionary. The key would be the text you're counting (1 and 21 according to your example), the value stores the count itself (e.g. 1 and 2).
The structured data for your example would look like this:
{
'1': 1,
'21': 2
}
And the final code:
from tkinter import *
class MyApp(Frame):
def __init__(self, master):
super(MyApp, self).__init__(master)
#this is your counter variable
self.entries = {}
self.grid()
self.create_widgets()
def create_widgets(self):
Label(self, text = 'Your number:').grid(row = 0, column = 0, sticky = W)
self.num_ent = Entry(self)
self.num_ent.grid(row = 0, column = 1, sticky = W)
Button(self, text = 'Check', command = self.update).grid(row = 0, column = 2, sticky = W)
self.user_text = Text(self, width = 50, height = 40, wrap = WORD)
self.user_text.grid(row = 2, column = 0, columnspan = 3)
def update(self):
#get the new entry from the text field and strip whitespaces
new_entry = self.num_ent.get().strip()
#check if the entry is already in the counter variable
if new_entry in self.entries:
#if it is: increment the counter
self.entries[new_entry] += 1
else:
#if it's not: add it and set its counter to 1
self.entries[new_entry] = 1
#delete the whole text area
self.user_text.delete('0.0', END)
#get every entry from the counter variable, sorted alphabetically
for key in sorted(self.entries):
#insert the entry at the end of the text area
self.user_text.insert(END, '{}: number of entries({})\n'.format(key, self.entries[key]))
root = Tk()
root.geometry('410x200')
root.title('Entries counter')
app = MyApp(root)
root.mainloop()

Python: Waiting for the enter key OR button press (Text Based Adventure with GUI)

Hi I am making a text based adventure in python and am having trouble with taking the user input, the text the user reads is in one text box and the input goes in an entry box.
I don't know how to get it to wait for the user to press enter or for a button to be pressed on the actual GUI.
I have tried:
textin.bind('<Return>', get_input)
but that didn't work for some reason I couldn't work out.
I have also tried:
import msvcrt as m
def wait():
m.getch()
but that made the GUI not show up or I wasn't using it properly.
Another thing I have tired is:
import time
time.sleep(5.0)
but that had the same problem of the GUI not showing up until after the countdown.
I cannot use
input()
as I am using a GUI and if I use that then the GUI won't show up until after or some other problem (I may be wrong, I'm still new to some of this)
I need to know how I can get it to take the text in the entry when the user presses enter OR a button on the GUI, and all that needs to be in a function so that the main game can wait for them to enter a command.
The code so far:
import tkinter as tk
def get_input(): #the button I put in had problems
player_command = textin.get() #if this function wasn't before it
root = tk.Tk()
frame = tk.Frame(root)
frame.grid(row = 0, column = 0)
textout = tk.Text(frame, width = 50, height = 23)
scroll = tk.Scrollbar(frame)
textin = tk.Entry(frame, width = 50)
button = tk.Button(frame, text = 'Submit', command = get_input)
textout.grid(row = 0, columnspan = 2, sticky = tk.W + tk.E)
textin.grid(row = 1, column = 0, sticky = tk.W + tk.E)
button.grid(row = 1, column = 1, sticky = tk.W + tk.E)
scroll.grid(row = 0, column = 1, sticky = tk.N + tk.S + tk.E)
scroll.config(command = textout.yview)
def main_menu():
textout.configure(state = 'normal')
textout.insert(tk.END, "Welcome to The Adventure\n")
textout.insert(tk.END, "What would you like to do?\n")
textout.insert(tk.END, "Continue\n")
textout.insert(tk.END, "New Game\n")
textout.insert(tk.END, "Help\n")
textout.configure(state = 'disabled')
while True:
if player_command == 'continue':
load_game() #other function
elif player_command == 'new game':
character_creation() #other function
elif player_command == 'help':
help_info() #other function
else:
textout.configure(state = 'normal')
textout.insert(tk.END, "Unknown command, type 'help' for hints")
textout.configure(state = 'disabled')
main_menu()
root.mainloop()
Thanks in advance.
Here Is an example of taking user input from text box.
Note that in this example Enter key is used to get the string on current line and submit button is used to print the currently held data.
import Tkinter as tk
class Test(object):
def __init__(self, root):
self.laststat=0#just to check multiple <Enter key> press do not delete the data
self.currString=""
self.tempString=""
self.text = tk.Text(root)
self.text.bind('<Key>', self.stripLine)
self.text.pack(side=tk.LEFT)
self.text.focus()
self.button = tk.Button(root, text = 'Submit', command = self.printData)
self.button.pack(side=tk.LEFT)
def stripLine(self, event):
val=('{k!r}'.format(k = event.char))[1:-1]
if val=='\\r' and self.laststat==0:
self.currString=self.tempString
self.tempString=""
self.laststat=1
elif val!='\\r':
self.tempString+=val
self.laststat=0
def printData(self):
print 'Current String is :'+self.currString
#print 'temp String is :'+self.tempString
root = tk.Tk()
A = Test(root)
root.mainloop()
Also note that you can add similar functions (similar to stripLine) to handle backspace and similar other key presses

Debugging RadioButtons program in Python

from Tkinter import *
class Application (Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
Label(self, text = "Select the last book you read.").grid (row = 0, column = 0, sticky = W)
self.choice = StringVar()
Radiobutton (self,text = "Nausea by Jean-Paul Sartre",variable = self.choice,
value = "Wake up. This is a dream. This is all only a test of the emergency broadcasting system.",
command = self.update_text).grid (row = 2, column = 1, sticky = W)
Radiobutton (self,
text = "Infinite Jest by David Foster Wallace",
variable = self.choice,
value = "Because an adult borne without the volition to choose the thoughts that he thinks, is going to get hosed ;)",
command = self.update_text).grid (row = 3, column = 1, sticky = W)
Radiobutton (self,
text = "Cat's Cradle by Kurt Vonnegut",
variable = self.choice,
value = " \"Here we are, trapped in the amber of the moment. There is no why!\" ",
command = self.update_text.grid (row = 4, column = 1, sticky = W)
self.txt_display = Text (self, width = 40, height = 5, wrap = WORD)
self.txt_display.grid (row = 6, column = 0, sticky = W)
#There is only one choice value - self.choice. That can be "printed."
def update_text(self):
message = self.choice.get()
self.txt_display.delete (0.0, END)
self.txt_display.insert (0.0, message)
# The Main
root = Tk()
root.title ("The Book Critic One")
root.geometry ("400x400")
app = Application (root)
root.mainloop()
I keep getting a Syntax Error in the self.text_display_delete line which I can't seem to lose.
Any input would be greatly appreciated.
Take a look at the previous line - I only count one closing parenthesis, while you should have two:
Radiobutton (self,
text = "Cat's Cradle by Kurt Vonnegut",
variable = self.choice,
value = " \"Here we are, trapped in the amber of the moment. There is no why!\" ",
command = self.update_text.grid (row = 4, column = 1, sticky = W)) #<-- Missing that second paren
Usually if one line looks clean, the syntax error is on the previous line(s), and 99% of the time it's a missing paren.

Categories

Resources