Rock paper scissor game with python tkinter - python

I want to separate the GUI and the game logic using object oriented but when Im trying to display the "self.result" using tkinter.Label its show "PY VAR1".
Can anyone please help how to update the self.result?
rockpaperscissor.py
import random
class RockPaperScissor:
def __init__(self):
self.rock = 'rock'
self.paper = 'paper'
self.scissor = 'scissor'
self.playerA_win = 'player A win'
self.playerB_win = 'player B win'
self.draw = 'Its draw'
self.playerA_score = 0
self.playerB_score = 0
self.choices = {'rock': self.rock,
'paper': self.paper,
'scissor': self.scissor}
self.transition = {
(self.rock, self.rock): self.draw,
(self.rock, self.paper): self.playerB_win,
(self.rock, self.scissor): self.playerA_win,
(self.paper, self.rock): self.playerA_win,
(self.paper, self.paper): self.draw,
(self.paper, self.scissor): self.playerB_win,
(self.scissor, self.rock): self.playerB_win,
(self.scissor, self.paper): self.playerA_win,
(self.scissor, self.scissor): self.draw}
def play(self, playerA, playerB):
self.playerA_answer = self.choices[playerA]
self.playerB_answer = self.choices[playerB]
self.result = self.transition[self.playerA_answer,
self.playerB_answer]
def get_result(self):
return self.result
def computer():
choices = ('rock', 'paper', 'scissor')
playerB = random.choice(choices)
return playerB
if __name__ == "__main__":
rps = RockPaperScissor()
while True:
playerA = input('What is your guess? ')
playerB = computer()
rps.play(playerA,playerB)
print(rps.get_result())
and
rockpaperscissor_gui.py
import tkinter as tk
import rockpaperscissor as rps
class MyFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.value = tk.StringVar()
self.result = tk.StringVar()
self.choice = ('rock', 'paper', 'scissor')
self.rps = rps.RockPaperScissor()
for i in self.choice:
self.radio = tk.Radiobutton(self,
text=i,
variable=self.value,
value=i).pack()
self.button = tk.Button(self,
text='play',
command=self.play).pack()
self.label = tk.Label(self,
text=self.result).pack()
def play(self):
playerA = self.value.get()
playerB = rps.computer()
self.rps.play(playerA, playerB)
self.result.set('result: {0}'.format(self.result))
if __name__ == '__main__':
MyFrame().mainloop()
this is the screenshot image

thanks for answer now its working!
this is the new code
#rockpaperscissor_gui.py
import tkinter as tk
import random as rn
import rockpaperscissor as rps
class RockPaperScissor:
def __init__(self):
self.rps = rps.RockPaperScissor()
self.root = tk.Tk()
self.playerA = tk.StringVar()
self.playerA.set('Pick your answer')
self.playerB = tk.StringVar()
self.playerB.set('Pick your answer')
self.result = tk.StringVar()
self.rps.playerA_score = tk.StringVar()
self.rps.playerB_score = tk.StringVar()
self.choices = ('rock', 'paper', 'scissor')
self.label_choices = (self.playerA, self.playerB, self.result)
for item in self.label_choices:
self.label = tk.Label(self.root, textvariable=item)
self.label.pack()
for item in self.choices:
self.radiobutton = tk.Radiobutton(self.root, text=item,
variable=self.playerA,
value=item)
self.radiobutton.pack()
self.button = tk.Button(self.root,
text='update',
command=self.update).pack()
self.root.mainloop()
def update(self):
self.playerB_answer = rn.choice(self.choices)
self.playerB.set(self.playerB_answer)
player = self.playerA.get()
computer = self.playerB.get()
self.rps.play(player, computer)
answer = self.rps.get_result()
self.result.set(answer)
if __name__ == '__main__':
RockPaperScissor()

You have to use textvariable in Label and display self.rps.get_result()
btw: you don't have to assign widget to variable if you don't use this variable.
Code could be like this
import tkinter as tk
import rockpaperscissor as rps
class MyFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.value = tk.StringVar()
self.result = tk.StringVar()
self.choice = ('rock', 'paper', 'scissor')
self.rps = rps.RockPaperScissor()
for i in self.choice:
tk.Radiobutton(self,
text=i,
variable=self.value,
value=i).pack()
tk.Button(self, text='play', command=self.play).pack()
tk.Label(self, textvariable=self.result).pack() # textvariable
def play(self):
playerA = self.value.get()
playerB = rps.computer()
self.rps.play(playerA, playerB)
self.result.set('result: {0}'.format(self.rps.get_result())) # get_result()
if __name__ == '__main__':
MyFrame().mainloop()

Related

PYTHON Attribute Error while running this GUI

So, I'm following a tutorial on making a simple calculator, and I'm Getting an attribute error AttributeError:'_tkinter.tkapp' object has no attribute 'displayframe' , apparently, the attribute doesn't exist in the source code even if it has been defined? would be grateful if someone helped
from tkinter import *
SMALL_FONT_STYLE = "Arial 16"
LIGHT_GRAY = "#F5F5F5"
LABEL_COLOR = "#25265E"
LARGE_FONT_STYLE = "Arial 40 bold"
WHITE = "#FFFFFF"
class Calculator(Tk):
def __init__(self):
super().__init__()
self.geometry("375x677")
self.resizable(0,0)
self.title("Calculator")
self.total_expression = "0"
self.current_expression = "0"
self.total_label, self.label = self.create_display_labels()
self.digits = {7:(1,1), 8:(1,2), 9:(1,3), 4:(2,1), 5:(2,2), 6:(2,3), 1:(3,1),2:(3,2), 3:(3,3), 0:(4,2), '.':(4,1)}
self.create_digits_buttons()
self.display_frame = self.create_display_frame()
self.buttons_frame = self.create_buttons_frame()
def create_display_labels(self):
total_label = Label(self.display_frame, text=self.total_expression, anchor=E, bg=LIGHT_GRAY, fg=LABEL_COLOR, padx=24, font=SMALL_FONT_STYLE)
total_label.pack(expand=True, fill="both")
label = Label(self.display_frame, text=self.total_expression, anchor=E, bg=LIGHT_GRAY, fg=LABEL_COLOR, padx=24, font=LARGE_FONT_STYLE)
label.pack(expand=True, fill="both")
return total_label, label
def create_display_frame(self):
frame = Frame(self, height=221, bg=LIGHT_GRAY)
frame.pack(expand=True, fill="both")
return frame
def create_buttons_frame(self):
frame = Frame(self)
frame.pack(expand=TRUE, fill="both")
return frame
def create_digits_buttons(self):
for digit, grid_value in self.digits.items():
button = Button(self.buttons_frame, text= str(digit), bg=WHITE, fg=LABEL_COLOR)
button.grid(row = grid_value[0], column = grid_value[1], sticky=NSEW)
if __name__ == '__main__':
Calc = Calculator()
Calc.mainloop()```
This error is because you call self.create_display_labels() before calling self.create_display_frame(). You also call self.create_digits_buttons() before calling self.create_buttons_frame().
Move self.create_display_labels() and self.create_digits_buttons() below self.create_display_frame() and self.create_buttons_frame(). Here is what __init__() should look like:
def __init__(self):
super().__init__()
self.geometry("375x677")
self.resizable(0,0)
self.title("Calculator")
self.total_expression = "0"
self.current_expression = "0"
self.digits = {7:(1,1), 8:(1,2), 9:(1,3), 4:(2,1), 5:(2,2), 6:(2,3), 1:(3,1),2:(3,2), 3:(3,3), 0:(4,2), '.':(4,1)}
self.display_frame = self.create_display_frame()
self.buttons_frame = self.create_buttons_frame()
self.create_digits_buttons() ### MOVED THIS LINE
self.total_label, self.label = self.create_display_labels() ### MOVED THIS LINE

How to add a command option like a tkinter Button in this custome widget?

I have tried to create a custom widget name OnOffButton but now i want to call a function when the widget is clicked like Button widget.
I want command option in my widget like tkinter.Button has.
Help would be really appreciated.
I am a beginner, so please forgive me if the code logic or the code formation is not good.
import tkinter as tk
class OnOffButton(tk.Frame):
def __init__(self, parent,barwidth=3,default='OFF',font='consolas 12 bold'):
tk.Frame.__init__(self, parent)
self.ON = "ON "
self.OFF = 'OFF'
self.space = ' '*barwidth
self.font = font
self.on_variable = tk.IntVar(self,value=0)
self.off_variable = tk.IntVar(self,value=0)
self.state = 0
self.on_btn = tk.Checkbutton(self, text=self.space, indicatoron=False, font=self.font,fg='green',\
onvalue=1, offvalue=0, variable=self.on_variable, command=self.click_on)
self.off_btn = tk.Checkbutton(self, text=self.OFF, indicatoron=False, font=self.font,fg='red',\
onvalue=1, offvalue=0, variable=self.off_variable, command=self.click_off)
self.on_btn.grid(row=0, column=0)
self.off_btn.grid(row=0, column=1)
if default.lower() == 'off':
self.off_btn.select()
self.on_btn.deselect()
else:
self.on_btn.select()
self.off_btn.deselect()
self.on_btn['text'] = self.ON
self.off_btn['text'] = self.space
def click_on(self):
if self.on_variable.get() == 0:
self.off_btn.select()
self.off_btn['text'] = self.OFF
self.on_btn['text'] = self.space
self.state = False
elif self.on_variable.get() == 1:
self.off_btn.deselect()
self.off_btn['text'] = self.space
self.on_btn['text'] = self.ON
self.state = True
def click_off(self):
if self.off_variable.get() == 0:
self.on_btn.select()
self.on_btn['text'] = self.ON
self.off_btn['text'] = self.space
self.state = True
elif self.off_variable.get() == 1:
self.on_btn.deselect()
self.on_btn['text'] = self.space
self.off_btn['text'] = self.OFF
self.state = False
if __name__ == '__main__':
root = tk.Tk()
root.geometry('200x200')
btn = OnOffButton(root)
btn.pack()
root.mainloop()
Simply add a command option in the __init__() function and call the passed callback inside click_on() and click_off() function:
from inspect import isfunction
class OnOffButton(tk.Frame):
def __init__(self, ..., command=None): # added command option
...
self.command = command if isfunction(command) else None
...
def click_on(self):
...
if self.command:
self.command()
def click_off(self):
...
if self.command:
self.command()
...
btn = OnOffButton(root, command=lambda: print("clicked"))
...

communication between tkinter toplevels

I'm working on a little project and made a little on-screen keyboard as a tkinter Toplevel
my application is buildt like this:
Root-Window (Tk-Widget)
input 1 (Entry-Widget)
input 2 (Entry-Widget)
input 3 (Text-Widget)
on_screen-keyboard (Toplevel-Widget)
the Toplevel-Widget contains Buttons, with callbacks that should enter text in the entries (just like keyboard-Buttons)
What I want is a communication between children of the keyboard/the keyboard and the last active input-Widget. My Problem is, that I don't know, how to say the keyboard, to which input-Widget it should send the message.
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.active_input = tk.Variable(value=None)
ttk.Button(self, text="show Keyboard", command=lambda: Keyboard(self)).pack()
self.text = tk.StringVar(value="")
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", lambda e: self.active_input.set(self.input1))
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", lambda e: self.active_input.set(self.input2))
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", lambda e: self.active_input.set(self.input3))
self.input1.pack()
self.input3.pack()
self.input2.pack()
class Keyboard(tk.Toplevel):
OPENED = False
NAME = "- Keyboard -"
NUM = [{"text":"1", "width":1},
{"text":"2", "width":1},
{"text":"3", "width":2}]
CHAR= [{"text":"A", "width":1},
{"text":"B", "width":1},
{"text":"C", "width":2}]
def __init__(self, master):
if not Keyboard.OPENED:
Keyboard.OPENED = True
print("keyboard opened!")
self.master = master
tk.Toplevel.__init__(self, master)
self.title(self.NAME)
self.protocol("WM_DELETE_WINDOW", self.close)
self.keyb_nb = ttk.Notebook(self)
self.keyb_nb.pack()
self.num_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.num_tab, Keyboard.NUM,2)
self.keyb_nb.add(self.num_tab, text="123")
self.char_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.char_tab, Keyboard.CHAR, 2)
self.keyb_nb.add(self.char_tab, text="ABC")
def createPad(self, master, pad:list, max_col):
self.co_count = 0
self.ro = 1
for button in pad:
button["id"] = ttk.Button(master, width=6*button["width"], text=button["text"], command=self.bclicked(button))
if self.co_count >= max_col:
self.ro = self.ro + 1
self.co_count = 0
button["id"].grid(row=self.ro, columnspan=button["width"], column=self.co_count)
self.co_count = self.co_count+button["width"]
def bclicked(self, button:dict):
"""
reciver = self.master.active_input #I think the Problem here is, that the variable contains a string, not a widget
reciever.focus_force()
reciever.insert(index=tk.INSERT, string=button["text"])
"""
pass
def close(self):
Keyboard.OPENED = False
self.destroy()
print("keyboard closed!")
root = MainWindow()
root.mainloop()
Here the init of the Mainwindow and the bclicked of the Keyboard class are important...
the code is debug-ready
I would prefer a solution, similar to the communication in the internet (sender=button, receiver-id, message), but very welcome every working solution
btw: I'm also looking for a solution, how I don't have to force the input to focus and the Toplevel stays an the highest layer of the screen (that if I focus the Tk-Widget/one of the inputs/the button, the keyboard will stay in front of it)
SUMMARY: how do I find out, which of the 3 input-widgets was active at last, when the keyboard-toplevel has already the focus?
I may made more changes than needed, but mainly focus on the method keyboard_triger() and pass_key_to_master(), this two use the idea that the variable master implements, having access to call methods out of scope.
Olso the method set_focused_object() stores a reference to the last object beeng focused, note than it stores the widget and not the event, it's easyer than searching each time the object
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def keyboard_triger(self, key):
# to identify wath object is just use
# isinstance(self.active_input, ttk.Entry)
self.active_input.insert(tk.END, key)
def new_keyboard(self):
Keyboard(self)
def set_focused_object(self, event):
self.active_input = event.widget
def __init__(self):
tk.Tk.__init__(self)
self.active_input = None
ttk.Button(self, text="Show Keyboard", command=self.new_keyboard).pack()
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", self.set_focused_object)
self.input1.pack()
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", self.set_focused_object)
self.input2.pack()
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", self.set_focused_object)
self.input3.pack()
class Keyboard(tk.Toplevel):
def pass_key_to_master(self, key):
self.master.keyboard_triger(key)
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.master = master
self.title('Keyboard')
# this way of agruping keys stores the kwags
# of the drawing method
keys = {
'A': {'x': 0, 'y': 0},
'B': {'x': 20, 'y': 20},
'C': {'x': 50, 'y': 50}
}
# expected structure
# {string key: reference to the button}
self.buttons = {}
for i in keys:
self.buttons[i] = tk.Button( # i=i is required to make a instance
self, text=i, command=lambda i=i: self.pass_key_to_master(i)
)
self.buttons[i].place(**keys[i])
if __name__ == '__main__':
root = MainWindow()
root.mainloop()
Your code maybe could have a better construction.(But I didn't revise your code construction.)
Followed by your code,I use a global variable.And fix some errors in your code.And it could work normally in my computer.
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.active_input = tk.Variable(value=None)
ttk.Button(self, text="show Keyboard", command=lambda: Keyboard(self)).pack()
global focusedWidget
focusedWidget = None
self.text = tk.StringVar(value="")
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", self.getFocusWidget)
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", self.getFocusWidget)
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", self.getFocusWidget)
self.input1.pack()
self.input3.pack()
self.input2.pack()
def getFocusWidget(self,event): # this function could be a static function
global focusedWidget
focusedWidget = event.widget
class Keyboard(tk.Toplevel):
OPENED = False
NAME = "- Keyboard -"
NUM = [{"text":"1", "width":1},
{"text":"2", "width":1},
{"text":"3", "width":2}]
CHAR= [{"text":"A", "width":1},
{"text":"B", "width":1},
{"text":"C", "width":2}]
def __init__(self, master):
if not Keyboard.OPENED:
Keyboard.OPENED = True
print("keyboard opened!")
self.master = master
tk.Toplevel.__init__(self, master)
self.title(self.NAME)
self.protocol("WM_DELETE_WINDOW", self.close)
self.keyb_nb = ttk.Notebook(self)
self.keyb_nb.pack()
self.num_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.num_tab, Keyboard.NUM,2)
self.keyb_nb.add(self.num_tab, text="123")
self.char_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.char_tab, Keyboard.CHAR, 2)
self.keyb_nb.add(self.char_tab, text="ABC")
def createPad(self, master, pad:list, max_col):
self.co_count = 0
self.ro = 1
for button in pad:
button["id"] = ttk.Button(master, width=6*button["width"], text=button["text"], command=lambda button=button:self.bclicked(button)) # this lambda expression has some errors.
if self.co_count >= max_col:
self.ro = self.ro + 1
self.co_count = 0
button["id"].grid(row=self.ro, columnspan=button["width"], column=self.co_count)
self.co_count = self.co_count+button["width"]
def bclicked(self, button:dict):
global focusedWidget
"""
reciver = self.master.active_input #I think the Problem here is, that the variable contains a string, not a widget
reciever.focus_force()
reciever.insert(index=tk.INSERT, string=button["text"])
"""
if not focusedWidget: # If user hasn't click a entry or text widget.
print("Please select a entry or text")
return
if focusedWidget.widgetName=='ttk::entry': # use if statement to check the type of selected entry.
focusedWidget.insert(index=tk.INSERT,string=button["text"])
else:
focusedWidget.insert("end",button["text"])
def close(self):
Keyboard.OPENED = False
self.destroy()
print("keyboard closed!")
root = MainWindow()
root.mainloop()

Python Tkinter threading

I need help with a program which uses tkinter. So I try to use a button to cycle trough some pictures, but there are two cycles and when i press one button either disappears or goes back to the first one (it's kinda hard to explain). I was asking myself if I could use some threading here and I need help since I've never used it before.
This is the part of the code:
square1 = Image.open("Square1.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=30, y=100)
square1 = Image.open("Square1a.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=435, y=100)
next = Button(self.windowSq, text="Next", font=self.customFont, relief=GROOVE, command=self.next, cursor='hand2')
next.place(x=185, y=380)
self.num = 0
next1 = Button(self.windowSq, text="Next", font=self.customFont, relief=GROOVE, command=self.next1, cursor='hand2')
next1.place(x=600, y=380)
self.num1 = 0
def next(self):
self.num = self.num + 1
if self.num == 1:
self.square1img.destroy()
square2 = Image.open("Square2.jpg")
square2r = ImageTk.PhotoImage(square2)
self.square2img = Label(self.windowSq, image=square2r)
self.square2img.image = square2r
self.square2img.place(x=30, y=100)
elif self.num == 2:
self.square2img.destroy()
square3 = Image.open("Square3.jpg")
square3r = ImageTk.PhotoImage(square3)
self.square3img = Label(self.windowSq, image=square3r)
self.square3img.image = square3r
self.square3img.place(x=30, y=100)
elif self.num == 3:
self.square3img.destroy()
square4 = Image.open("Square4.jpg")
square4r = ImageTk.PhotoImage(square4)
self.square4img = Label(self.windowSq, image=square4r)
self.square4img.image = square4r
self.square4img.place(x=30, y=100)
elif self.num == 4:
self.square4img.destroy()
square5 = Image.open("Square5.jpg")
square5r = ImageTk.PhotoImage(square5)
self.square5img = Label(self.windowSq, image=square5r)
self.square5img.image = square5r
self.square5img.place(x=30, y=100)
elif self.num == 5:
self.square5img.destroy()
square1 = Image.open("Square1.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=30, y=100)
self.num = 0
self.windowSq.after(50000, self.next)
def next1(self):
self.num1 = self.num1 + 1
if self.num1 == 1:
self.square1img.destroy()
square2 = Image.open("Square2a.jpg")
square2r = ImageTk.PhotoImage(square2)
self.square2img = Label(self.windowSq, image=square2r)
self.square2img.image = square2r
self.square2img.place(x=435, y=100)
elif self.num1 == 2:
self.square2img.destroy()
square3 = Image.open("Square3a.jpg")
square3r = ImageTk.PhotoImage(square3)
self.square3img = Label(self.windowSq, image=square3r)
self.square3img.image = square3r
self.square3img.place(x=435, y=100)
elif self.num1 == 3:
self.square3img.destroy()
square4 = Image.open("Square4a.jpg")
square4r = ImageTk.PhotoImage(square4)
self.square4img = Label(self.windowSq, image=square4r)
self.square4img.image = square4r
self.square4img.place(x=435, y=100)
elif self.num1 == 4:
self.square4img.destroy()
square5 = Image.open("Square5a.jpg")
square5r = ImageTk.PhotoImage(square5)
self.square5img = Label(self.windowSq, image=square5r)
self.square5img.image = square5r
self.square5img.place(x=435, y=100)
elif self.num1 == 5:
self.square5img.destroy()
square1 = Image.open("Square1a.jpg")
square1r = ImageTk.PhotoImage(square1)
self.square1img = Label(self.windowSq, image=square1r)
self.square1img.image = square1r
self.square1img.place(x=435, y=100)
self.num1 = 0
self.windowSq.after(50000, self.next1)
The whole program is in a class (if you are wondering...)
class Window(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.master.resizable(0, 0)
master.title("Arcade Games")
master.geometry("800x600+560+240")
You have a lot of redundant code above. The idea is to first store the images in a list and then cycle through the list. You can have 2 buttons that call 2 different functions (one for each list), 2 lists of images, and 2 counters to keep your place in each list, and then change the image on a Label from whichever list you want (I use a button as below, and note that only one button is created-never destroyed, and just the image is changed each time). Or you can use one class, and 2 instances of the class, passing a different list of images to be loaded to each instance. This is just a simple proof of concept program. Click on the button/image to change it.
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
class ChangeImage():
def __init__(self, root):
self.photos=[]
self.load_images()
self.image_num=0
self.btn = tk.Button(root, image=self.photos[self.image_num], command=self.next_image)
self.btn.grid(row=0)
tk.Button(root, text="Exit", bg="orange", command=root.quit).grid(row=1)
def next_image(self):
self.image_num += 1
if self.image_num >= len(self.photos):
self.image_num=0
## pipe the next image to be displayed to the button
self.btn["image"]=self.photos[self.image_num]
def load_images(self):
""" copy data images to a list that is an instance variable
"""
ladybug_gif_b64='''\
R0lGODlhIAAgALMAAP///wAAADAwMP99Hf8AAP+lAP//AMopUwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAACH5BAAAAAAALAAAAAAgACAAAwTHEMhJq714hp3lDh0GiqH2UWOVAt96pUIsBLKglWg87Dwv
4xMBj0Asxgg+XKxwLBJrxUGsI5TKnARoVHoLDp5XbNP5cwmNAqwa/aOc13ByrfKOw2UGw1SSxrb+
AWIxeXsAaX92UDQ1Nh6BdneMhQIHkHGSjYaVlmt4epmacp19YAKEoJRspKWrjBapWWGqcm1uB5tj
ok4HZa+3m5wEt5kuhpTAcb+FVL/NzspAfDHPysslMJjEIS0oLygnOMVd0SwcHeDk6errEQA7
'''
grape_gif='''\
R0lGODlhIAAgALMAAAAAAAAAgHCAkC6LV76+vvXeswD/ANzc3DLNMubm+v/6zS9PT6Ai8P8A////
/////yH5BAEAAAkALAAAAAAgACAAAAS00MlJq7046803AF3ofAYYfh8GIEvpoUZcmtOKAO5rLMva
0rYVKqX5IEq3XDAZo1GGiOhw5rtJc09cVGo7orYwYtYo3d4+DBxJWuSCAQ30+vNTGcxnOIARj3eT
YhJDQ3woDGl7foNiKBV7aYeEkHEignKFkk4ciYaImJqbkZ+PjZUjaJOElKanqJyRrJyZgSKkokOs
NYa2q7mcirC5I5FofsK6hcHHgsSgx4a9yzXK0rrV19gRADs=
'''
house='''R0lGODdhFQAVAPMAAAQ2PESapISCBASCBMTCxPxmNCQiJJya/ISChGRmzPz+/PxmzDQyZDQyZDQy
ZDQyZCwAAAAAFQAVAAAElJDISau9Vh2WMD0gqHHelJwnsXVloqDd2hrMm8pYYiSHYfMMRm53ULlQ
HGFFx1MZCciUiVOsPmEkKNVp3UBhJ4Ohy1UxerSgJGZMMBbcBACQlVhRiHvaUsXHgywTdycLdxyB
gm1vcTyIZW4MeU6NgQEBXEGRcQcIlwQIAwEHoioCAgWmCZ0Iq5+hA6wIpqislgGhthEAOw==
'''
## could also be a list of files passed to the class
for photo in (ladybug_gif_b64, grape_gif, house):
self.photos.append(tk.PhotoImage(data=photo))
root=tk.Tk()
CI=ChangeImage(root)
root.mainloop()

Python Tkinter attribute error entry in random letter typing test

Traceback (most recent call last):
File "C:/Users/Brett/Documents/shellrunpractice", line 83, in <module>
app = simpleapp_tk(None)
File "C:/Users/Brett/Documents/shellrunpractice", line 9, in __init__
self.initialize()
File "C:/Users/Brett/Documents/shellrunpractice", line 22, in initialize
command=self.usertypetest(0),fg="black",bg="green")
File "C:/Users/Brett/Documents/shellrunpractice", line 66, in usertypetest
self.keeptime(num1)
File "C:/Users/Brett/Documents/shellrunpractice", line 44, in keeptime
self.entry.selection_range(0, Tkinter.END)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1845, in __getattr__
return getattr(self.tk, attr)
AttributeError: entry
Here is the code:
import Tkinter
import random
from time import sleep
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
self.grid()
self.labelVariable = Tkinter.StringVar()
label = Tkinter.Label(self,textvariable=self.labelVariable,anchor="w",fg="blue",bg="gold")
label.grid(column=0,row=0,sticky='EW')
self.labelVariable.set(u"Press button to begin!")
self.button = Tkinter.Button(self,text=u"Start",
command=self.usertypetest(0),fg="black",bg="green")
self.button.grid(column=2,row=0)
self.labelVariable2 = Tkinter.StringVar()
label2 = Tkinter.Label(self,textvariable=self.labelVariable2,anchor="w",fg="blue",bg="gold")
label2.grid(column=1,row=0,sticky='EW')
self.labelVariable2.set(u'Time')
self.entryVariable = Tkinter.StringVar()
self.entry = Tkinter.Entry(self,textvariable=self.entryVariable,fg="black",bg="white")
self.entry.grid(column=0,row=1,columnspan=2,sticky='EW')
self.entryVariable.set(u"")
self.grid_columnconfigure(0,weight=1)
self.grid_rowconfigure(0,weight=1)
self.resizable(True,True)
def keeptime(self,num1):
self.entry.selection_range(0, Tkinter.END)
timer = num1
t = 0
while timer < 1:
self.labelVariable2.set(t)
sleep(.01)
t += .01
def usertype(self):
randletter = random.choice('qwer')
self.labelVariable.set("Press "+randletter)
userinput = self.entryVariable.get
while userinput == '':
pass
if userinput == randletter:
return 'Correct'
else:
return 'Incorrect'
def usertypetest(self,num1):
self.keeptime(num1)
for x in range(20):
result = usertype()
print result
if result == 'Correct':
y = y+5
else:
y = y-2
timer += 1
self.labelVariable.set(str(y)+' is your score')
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('LoL Practice')
app.geometry("700x50")
app.configure(background='black')
app.mainloop()
I don't know why I am receiving this problem as I am just starting to learn Tkinter and I am not very good yet.
The goal of this program is that when the user clicks start, a timer will start, printing to a label, and they will be shown letters randomly chosen from (Q,W,E,R), which they must type as fast as possible. The program will time them and give them a score based on their errors at the end, and also stop the timer.
I am wondering if you guys could find any other errors in my code that could be causing that, and if so how to do it. I realize my code is very bad, I'm just starting in Tkinter, and I'm not entirely sure how everything works yet.
Any general comments about how I could improve my coding would also be greatly appreciated, as would any comments on how I could write a program to do what I want, as I feel my current method is not practical/functional.
command= expect only function name - without () and parameters.
Using command=self.usertypetest(0) you run self.usertypetest(0)
and its result is assigned to command=.
But self.usertypetest(0) use self.entry which wasn't defined yet.
self.entry is defined after Tkinter.Button(...command=self.usertypetest(0)...)
If you need to assing function with parameters then use lambda
command=lambda:self.usertypetest(0)
And now it works.
EDIT:
Full working version:
(I changed some variable names)
import Tkinter
import random
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
self.started = False # True when timer is running
def initialize(self):
self.grid()
self.infoVariable = Tkinter.StringVar()
self.labelInfo = Tkinter.Label(self, textvariable=self.infoVariable, anchor="w", fg="blue", bg="gold")
self.labelInfo.grid(column=0, row=0, sticky='EW')
self.infoVariable.set(u"Press button to begin!")
self.buttonStart = Tkinter.Button(self, text=u"Start", command=self.on_buttonStart, fg="black", bg="green")
self.buttonStart.grid(column=2, row=0)
self.timeVariable = Tkinter.StringVar()
self.labelTime = Tkinter.Label(self, textvariable=self.timeVariable, anchor="w", fg="blue", bg="gold")
self.labelTime.grid(column=1, row=0, sticky='EW')
self.timeVariable.set(u'Time')
self.entryVariable = Tkinter.StringVar()
self.entry = Tkinter.Entry(self, textvariable=self.entryVariable, fg="black", bg="white")
self.entry.grid(column=0, row=1, columnspan=2, sticky='EW')
self.entryVariable.set(u"")
self.entry.bind('<Key>', self.on_key) # event
self.grid_columnconfigure(0,weight=1)
self.grid_rowconfigure(0,weight=1)
self.resizable(True,True)
def on_buttonStart(self):
if not self.started:
# reset values
self.started = True
self.number_of_letters = 20
self.score = 0
self.time = 0.0
# select first letter
self.randletter = random.choice('qwer')
# show first letter and score
self.infoVariable.set('Score:' + str(self.score)+' | Press ' + self.randletter)
# start timer
self.after(100, self.timer)
def on_key(self, event):
if not self.started:
self.entryVariable.set('')
else:
if event.char == self.randletter:
print 'Correct', event.char
self.score += 5
else:
print 'Incorrect', event.char
self.score -= 2
self.number_of_letters -= 1
if self.number_of_letters == 0:
self.started = False
self.entryVariable.set('')
self.infoVariable.set('Score:' + str(self.score))
else:
self.randletter = random.choice('qwer')
self.infoVariable.set('Score:' + str(self.score)+' | Press ' + self.randletter)
def timer(self):
if self.started:
self.time += .1
self.timeVariable.set('Time: ' + str(round(self.time,1)) )
self.after(100, self.timer)
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('LoL Practice')
app.geometry("700x50")
app.configure(background='black')
app.mainloop()

Categories

Resources