I need help understanding how I can use the checkbox I've made turn a part of the program off when checked on and turn another part off when the checkbox is off. My idea is that when the checkbox is on, I want the addPercTip(self) section to be turned on and the addRateTip to be turned off, and vice-versa when the checkbox is off. PercTip off and RateTip on. My problem right now is that in my calculations, it is trying to take info from both parts, so one of them needs to be off. Any help would be enormously appreciated!
from Tkinter import *
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.headerFont = ("Times", "16", "italic")
self.title("Restaurant Tipper")
self.addOrigBill()
self.addChooseOne()
self.addPercTip()
self.addRateTip()
self.addOutput()
def addChooseOne(self):
Label(self, text = "Check ON for % check OFF for rating!",
font = self.headerFont).grid(row = 2, column = 1)
self.checkVar = IntVar()
self.chkCheck = Checkbutton(self, variable = self.checkVar)
self.chkCheck.grid(row = 3, column = 1)
def calculate(self):
bill = float(self.txtBillAmount.get())
percTip = self.percVar
rateTip = int(self.scrScale.get())
tip = bill * percTip
self.lblTip["text"] = "%.2f" % tip
totalBill = tip + bill
self.lblTotalBill["text"] = "%.2f" % totalBill
if rateTip <= 2:
percTip = .10
elif 3 <= rateTip <= 4:
percTip = .12
elif 5 <= rateTip <= 6:
percTip = .15
elif 7 <= rateTip <= 8:
percTip = .17
elif 9 <= rateTip <= 10:
percTip = .20
else:
self.lblTotalBill["text"] = "Something is wrong"
def main():
app = App()
app.mainloop()
if __name__ == "__main__":
main()
When you instantiate a checkbutton you can set a command attribute. This is a function that will be called whenever the button is checked.
self.chkCheck(self, variable = self.checkVar, command = doStuff)
def doStuff(self)
print 'doing stuff'
EDIT:
As to the comment below:
def doStuff(self):
if self.checkVar.get() == 1: <<<1 is the 'checked value'
percTip = True
rateTip = False
However, you don't actually need to do that. In your calculate() function you could simply call self.checkVar.get() and if it is 1 then evaluate and if 0 (unchecked) then evaluate differently etc.
Related
When I try to run this code, a ValueError appears alluding to the function numRandom. I though Python could pass a string representation of a int to an int.
import tkinter
import random
window = tkinter.Tk()
window.geometry('600x500')
x = random.randint(1,300)
remainingTime = True
Attempts = 4
def numRamdom():
global Attempts
while Attempts > 0:
numWritten = int(entryWriteNumber.get())
if numWritten > x:
lblClue.configure(text = 'Its a bigger number')
Attempts = Attempts -1
if numWritten < x:
lblClue.configure(text = 'Its a smaller number')
Attempts = Attempts -1
if numWritten == x:
lblClue.configure(text = 'Congratulations ;)')
remainingTime = False
return remainingTime, countdown(0)
if Attempts == 0:
remainingTime = False
return remainingTime, countdown(0), Attempts, gameOver()
entryWriteNumber = tkinter.Entry(window)
entryWriteNumber.grid(column = 0, row = 1, padx = 10, pady = 10)
numRamdom()
window.mainloop()
The problem is because when the code is ran, it directly calls numRamdom(), that is, initially the entry widgets are empty, and they run it with those empty entry widget and hence the error. So just assign a button and a command, like:
b = tkinter.Button(root,text='Click me',command=numRamdom)
b.grid(row=1,column=0)
Make sure to say this before the mainloop() after the def numRamdom():. The button just runs the function only when the button is clicked.
Or if you want button-less then try:
METHOD-1:
root.after(5000,numRamdom) #after 5 sec it will execute function
But keep in mind, if the user doesn't enter properly in 5 sec then some error would pop up.
METHOD-2:
def numRamdom(event):
......
entryWriteNumber.bind('<Return>',numRamdom)
This is so that, if you press enter key in the entry widget(after entering data) it will run the function.
Hope this helps, do let me know if any errors.
Cheers
Here's a fully working example based on your code. Your problem was trying to convert the contents of the Entry before anything was inside of it. To fix this problem, you can add a button which calls the command numRamdom()
import tkinter
import random
window = tkinter.Tk()
window.geometry('600x500')
x = random.randint(1,300)
remainingTime = True
Attempts = 4
def numRamdom():
global Attempts, lblClue, x
if Attempts > 0:
numWritten = int(entryWriteNumber.get())
if numWritten < x:
lblClue.configure(text = 'Its a bigger number')
Attempts = Attempts -1
elif numWritten > x:
lblClue.configure(text = 'Its a smaller number')
Attempts = Attempts -1
else:
lblClue.configure(text = 'Congratulations ;)')
remainingTime = False
#return remainingTime, countdown(0)
if Attempts == 0:
remainingTime = False
#return remainingTime, countdown(0), Attempts, gameOver()
else:
lblClue.configure(text = "You ran out of attempts!")
entryWriteNumber = tkinter.Entry(window)
entryWriteNumber.grid(column = 0, row = 1, padx = 10, pady = 10)
entryWriteButton = tkinter.Button(window, text = "Push me!", command = numRamdom)
entryWriteButton.grid(column = 1, row = 1)
lblClue = tkinter.Label(window)
lblClue.grid(row = 2, column = 1)
window.mainloop()
You'll still get an error if the value passed is not able to be converted into an integer, but that's easy to fix with an if statement.
I'm designing a Character Sheet from Dungeons & Dragons in Python, using Tkinter to take care of the graphical interface. However, I wanted to add an element (in this case a "proficiency" in a skill) to a list, if the checkbox corresponding to the same skill is active.
The checkbox buttons are working for some commands like exit ("root.destroy") but this in particulary doesn't seem to do anything.
I created a class Character, this Character has an empty Proficencies list and to add a proficiency to it, I created a function that did it whenever the matching checkbox value was set to True ("1")
import tkinter as tk
def modifier(score):
score = int(score)
return (score - 10) // 2
class Character:
proficiencies = []
abilities = {"Strength": 12, "Dexterity": 16, "Constitution": 14, "Intelligence": 10, "Wisdom": 16, "Charisma": 9}
skills = {"Athletics": 0, "Acrobatics": 0, "Sleight of Hand": 0, "Stealth": 0, "Arcana": 0, "History": 0,
"Investigation": 0, "Nature": 0, "Religion": 0,"Animal Handling": 0, "Insight": 0, "Medicine": 0,
"Perception": 0, "Survival": 0, "Deception": 0, "Intimidation": 0, "Performance": 0, "Persuasion": 0}
counter = 0
variables = []
skills = []
root = tk.Tk()
def addSkill():
if exec("var" + str(counter) + ".get() == 1"):
Character.proficiencies.append(skills[counter].replace('_', ' '))
elif exec("var" + str(counter) + ".get() == 0"):
pass
for skill in sorted(Character.skills.keys()):
skills.append(skill.replace(" ", "_"))
exec("var" + str(counter) + " = tk.IntVar()")
exec(skill.replace(" ", "") + "= tk.Checkbutton(root, text=skill, variable = var" + str(counter) + ", command = addSkill)")
exec(skill.replace(" ", "") + ".pack()")
variables.append("var" + str(counter))
counter += 1
counter = 0
root.mainloop()
index = 0
for skill in Character.skills:
if index == 0:
ability = "Strength"
elif index >= 1 and index <= 3:
ability = "Dexterity"
elif index >= 4 and index <= 8:
ability = "Intelligence"
elif index >= 9 and index <= 13:
ability = "Wisdom"
elif index >= 14:
ability = "Charisma"
if skill in Character.proficiencies:
Character.skills[skill] = 10 + (modifier(Character.abilities[ability]) + 2) * 2
else:
Character.skills[skill] = 10 + modifier(Character.abilities[ability]) * 2
index += 1
Here's an example of following Bryan Oakley's suggestion to avoid using exec() and not dynamically create named variables, I think you'll agree it's quite a bit easier to read and understand than the code you where using.
import tkinter as tk
SKILL_NAMES = ('Athletics', 'Acrobatics', 'Sleight of Hand', 'Stealth', 'Arcana',
'History', 'Investigation', 'Nature', 'Religion', 'Animal Handling',
'Insight', 'Medicine', 'Perception', 'Survival', 'Deception',
'Intimidation', 'Performance', 'Persuasion')
class Character:
proficiencies = []
abilities = {"Strength": 12, "Dexterity": 16, "Constitution": 14,
"Intelligence": 10, "Wisdom": 16, "Charisma": 9}
skills = dict.fromkeys(SKILL_NAMES, 0)
def modifier(score):
return (int(score) - 10) // 2
root = tk.Tk()
# Create tk.IntVars for holding value of each skill.
skill_vars = {skill: tk.IntVar() for skill in Character.skills}
# tkinter Checkbutton callback.
def addSkill(skill, var):
""" Add skill to proficiencies if Checkbutton is now checked. """
if var.get() == 1:
Character.proficiencies.append(skill)
# Create a Checkbutton corresponding to each skill.
for skill in Character.skills:
btn = tk.Checkbutton(root, text=skill, variable=skill_vars[skill],
command=lambda name=skill, var=skill_vars[skill]: addSkill(name, var))
btn.pack()
root.mainloop()
for index, skill in enumerate(Character.skills):
if index == 0:
ability = "Strength"
elif 1 <= index <= 3:
ability = "Dexterity"
elif 4 <= index <= 8:
ability = "Intelligence"
elif 9 <= index <= 13:
ability = "Wisdom"
elif index >= 14:
ability = "Charisma"
if skill in Character.proficiencies:
Character.skills[skill] = 10 + (modifier(Character.abilities[ability]) + 2) * 2
else:
Character.skills[skill] = 10 + modifier(Character.abilities[ability]) * 2
To whoever is having troubles with the same mistake, I think I've found the error.
Instead of:
def addSkill():
if exec("var" + str(counter) + ".get() == 1"):
Character.proficiencies.append(skills[counter].replace('_', ' '))
elif exec("var" + str(counter) + ".get() == 0"):
pass
I wrote:
def addSkill():
if var0.get() == 1:
Character.proficiencies.append(skills[0].replace('_', ' '))
if var1.get() == 1:
Character.proficiencies.append(skills[1].replace('_', ' '))
...
if var17.get() == 1:
Character.proficiencies.append(skills[17].replace('_', ' '))
And now it works :)
Ok I have a feeling that this is a simple simple issue but I have been staring at this code for about 10 hours now.
The issue I am having is in mastermind is that once I get it to recognize that I have the correct colors in the right spot I can get it to display the right spots with X and the wrong spots with O. I need to be able to convert that so instead of X and O I need it to tell the user that he/she has 2 blacks and one white
For example: The secret code is RGYB The user enters RGOY so then Python relays "You have 2 blacks(The R and G spots) and one 1 White (The Y because it's the right color just in the wrong index) As of right now I got it to display X for the right color in the right spot and anything else it is an O
I will post what I have been working with now but today I am at my wit's end
https://pastebin.com/HKK0T7bQ
if correctColor != "XXXX":
for i in range(4):
if guess[i] == tempCode[i]:
correctColor += "X"
if guess[i] != tempCode[i] in tempCode:
correctColor += "O"
print (correctColor + "\n")
if correctColor == "XXXX":
if attempts == 1:
print ("You think you are sweet because you got it right on the first try? Play me again!")
else:
print ("Well done... You needed " + str(attempts) + " attempts to guess.")
game = False
A few comments
X and O
you use X and 0 to denote the success, it will be easier and faster to use a list or tuple or booleans for this, that way you can use sum() to count how many colors and locations were correct. Then whether you represent that with X and O or red and white pins is a matter for later
compartmentalization
Your game logic (guess input, input validation, do you want to continue, etc) is mixed with the comparison logic, so it would be best to separate the different functions of your program into different methods.
This is an fineexample to introduce object oriented programming, but is so simple it doesn't need OO, but it can help. What you need is a method which takes a series of colours and compares it to another series of colours
Standard library
Python has a very extended standard library, so a lot of stuff you want to do probably already exists
Correct colours
to count the number of letters which occur in 2 strings, you can use collections.Counter
guess = "RGOY "
solution = "RGYB"
a = collections.Counter(guess)
b = collections.Counter(solution)
a & b
Counter({'G': 1, 'R': 1, 'Y': 1})
correct_colours = sum((a & b).values())
3
So the user guessed 3 colours correctly
Correct locations
can be solved with an easy list comprehension
[g == s for g, s in zip(guess, solution)]
[True, True, False, False]
sum(g == s for g, s in zip(guess, solution))
2
so the used put 2 colours on the correct location
This is a MasterMind I made in Python. Hope you like it and it helped you! :)
import random
import time
from tkinter import *
def select_level():
global level
level = level_selector.get()
root.destroy()
root = Tk()
level_selector = Scale(root, from_=1, to=3, tickinterval=1)
level_selector.set(0)
level_selector.pack()
Button(root, text="Select a difficulty level", command=select_level).pack()
mainloop()
cpc_1_digit = 0
cpc_2_digit = 0
cpc_3_digit = 0
cpc_4_digit = 0
p_1_digit = 0
p_2_digit = 0
p_3_digit = 0
p_4_digit = 0
correct_correct = 0
correct_wrong = 0
chances = 0
if level == 1:
chances = 15
elif level == 2:
chances = 10
else:
chances = 7
cpc_1_digit = random.randint(0, 9)
while cpc_2_digit == cpc_1_digit or cpc_2_digit == cpc_3_digit or cpc_2_digit ==
cpc_4_digit:
cpc_2_digit = random.randint(0, 9)
while cpc_3_digit == cpc_1_digit or cpc_3_digit == cpc_2_digit or cpc_3_digit ==
cpc_4_digit:
cpc_3_digit = random.randint(0, 9)
while cpc_4_digit == cpc_1_digit or cpc_4_digit == cpc_2_digit or cpc_4_digit ==
cpc_3_digit:
cpc_4_digit = random.randint(0, 9)
while chances > 0:
correct_correct = 0
correct_wrong = 0
answer = input("Enter a four-digit number with different digits (e.g 1476): ")
p_1_digit = int(answer[0])
p_2_digit = int(answer[1])
p_3_digit = int(answer[2])
p_4_digit = int(answer[3])
if p_1_digit == cpc_1_digit:
correct_correct = int(correct_correct) + 1
elif p_1_digit == cpc_2_digit or p_1_digit == cpc_3_digit or p_1_digit ==
cpc_4_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
if p_2_digit == cpc_2_digit:
correct_correct = correct_correct + 1
elif p_2_digit == cpc_1_digit or p_2_digit == cpc_3_digit or p_2_digit ==
cpc_4_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
if p_3_digit == cpc_3_digit:
correct_correct = int(correct_correct) + 1
elif p_3_digit == cpc_1_digit or p_3_digit == cpc_2_digit or p_3_digit ==
cpc_4_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
if p_4_digit == cpc_4_digit:
correct_correct = int(correct_correct) + 1
elif p_4_digit == cpc_1_digit or p_4_digit == cpc_3_digit or p_4_digit ==
cpc_2_digit:
correct_wrong = int(correct_wrong) + 1
else:
pass
print("")
if int(correct_correct) == 4:
print("Congratsulations! You found the computer's number!")
break
elif int(correct_wrong) > 0 or int(correct_correct) >= 1 and int(correct_correct)
< 4:
print("You got " + str(correct_correct) + " correct digit(s) in the correct
place, and " + str(correct_wrong) + " correct digit(s) but in wrong place.")
elif int(correct_correct) == 0 and int(correct_wrong) == 0:
print("You didn't guess any number, try again!")
else:
raise Exception("CheckError: line 69, something went wrong with the
comparings.")
exit()
print("")
chances = chances - 1
if chances == 0:
print("You lost... The secret number was " + str(cpc_1_digit) + str(cpc_2_digit)
+ str(cpc_3_digit) + str(cpc_4_digit) + ". Try again by rerunning the program.")
time.sleep(4)
I'm doing a mini-project on Coursera and I can run most parts of my code. However there's an error in the critical part about the game's match or not checking.
# implementation of card game - Memory
import simplegui
import random
# helper function to initialize globals
def new_game():
global turns, state, pairs, cards
turns = 0
state = 0
pairs = []
cards = range(9) * 2
random.shuffle(cards)
# define event handlers
def mouseclick(pos):
# add game state logic here
global turns, state, pairs
pointed = pos[0] // 50
if pointed in pairs:
pass
else:
if state == 0:
state = 1
pairs.append(pointed)
elif state == 1:
state = 2
turns += 1
label.set_text('Turns =' + str(turns))
pairs.append(pointed)
# if cards[pairs[-2]] == cards[[pairs[-1]]:
# flag = True
# else:
# flag = False
else:
state = 1
if flag == False:
del pairs[-2:]
pairs.append(pointed)
# cards are logically 50x100 pixels in size
def draw(canvas):
for n in range(1, 16):
canvas.draw_line((n * 50, 0), (n * 50, 100), 1, 'Green')
for n in pairs:
canvas.draw_line((n * 50 + 25, 0), (n * 50 + 25, 100), 50, 'White')
for n in pairs:
canvas.draw_text(str(cards[n]), (n * 50 + 15, 65), 50, 'Black')
# create frame and add a button and labels
frame = simplegui.create_frame("Memory", 800, 100)
frame.set_canvas_background('Red')
frame.add_button("Reset", new_game)
label = frame.add_label("Turns = 0")
# register event handlers
frame.set_mouseclick_handler(mouseclick)
frame.set_draw_handler(draw)
# get things rolling
new_game()
frame.start()
# Always remember to review the grading rubric
I commented out Line 31 to 34 and that's the part where I have a problem. The console keeps telling me Line 31: SyntaxError: bad input (' ') but I think the indentation is correctly made.
Please help me figure out why it's a 'bad input', thanks a lot!
Update:
Thanks to Russell's help, this function works now.
# define event handlers
def mouseclick(pos):
# add game state logic here
global turns, state, pairs, flag
pointed = pos[0] // 50
if pointed in pairs:
pass
else:
if state == 0:
state = 1
pairs.append(pointed)
elif state == 1:
state = 2
turns += 1
label.set_text('Turns =' + str(turns))
pairs.append(pointed)
if cards[pairs[-2]] == cards[pairs[-1]]:
flag = True
else:
flag = False
else:
state = 1
if flag == False:
del pairs[-2:]
pairs.append(pointed)
Your if statement is indented too far.
elif state == 1:
state = 2
turns += 1
label.set_text('Turns =' + str(turns))
pairs.append(pointed)
if cards[pairs[-2]] == cards[pairs[-1]]:
flag = True
else:
flag = False
else:
state = 1
if flag == False:
del pairs[-2:]
pairs.append(pointed)
I'm having trouble calling .update_idletasks() to redraw my canvas ( at the end of the .set_up() Class-method ).
If I use self.canv.update_idletasks( self ), the canvas draws the objects I want but gives the error
TypeError: update_idletasks() takes exactly 1 argument (2 given)
If I use self.canv.update_idletasks(), the canvas remains blank but doesn't produce any errors.
from Tkinter import *
class Animation(Frame):
def __init__(self,parent=None):
Frame.__init__(self,parent)
self.pack()
self.generation = 1
self.epoch = 1
self.set_up()
def set_up(self):
greeting_text = 'Generation ' + str(self.generation) + ', Epoch ' + str(self.epoch)
header = Label(self,text=greeting_text)
header.pack()
anframe = Frame(self,relief=SUNKEN)
anframe.pack(side='left',padx=10,pady=10)
self.canv = Canvas(anframe,width=800, height=800, bg='white') # 0,0 is top left corner
self.canv.pack(expand=YES, fill=BOTH,side='left')
buframe = Frame(self,relief=RAISED)
buframe.pack(side='right',fill=X,padx=10,pady=5)
start = Button(buframe,text='START',width=10,command=self.animate)
start.pack(expand=YES,fill=BOTH,side='top')
back = Button(buframe,text='Back',width=10)
back.pack(expand=YES,fill=BOTH,side='bottom')
nextgo= Button(buframe,text='Next',width=10)
nextgo.pack(expand=YES,fill=BOTH,side='bottom')
path = 'C:/Desktop/LearnNet/' + str(self.generation) + '_' + str(self.epoch) + '.txt'
data = open(path,'r')
lines = data.readlines()
food,moves = [],[]
for item in lines:
if item.strip() == 'f':
dat_type = 1
continue
elif item.strip() == 'a':
dat_type = 2
continue
if dat_type == 1:
temp = item.strip()
temp = item.split()
food.append([int(temp[0]),int(temp[1])])
if dat_type == 2:
temp = item.strip()
temp = item.split()
moves.append([int(temp[0]),int(temp[1]),int(temp[2])])
photos = []
for i in xrange(len(food)):
temp=PhotoImage(file='C:/Desktop/LearnNet/Food.gif')
photos.append(temp)
self.canv.create_image(food[i][0]*20,food[i][1]*20,image=photos[i],anchor=NW)
start_pos = moves[0]
picpath = self.orientation(start_pos[2])
animal = PhotoImage(file=picpath)
self.canv.create_image(moves[0][0]*20,moves[0][1]*20,image=animal,anchor=NW)
self.canv.update_idletasks(self)
def animate(self):
return 1
def orientation(self,angle):
if angle == 0:
picpath = 'C:/Desktop/LearnNet/PEast.gif'
elif angle == 90:
picpath = 'C:/Desktop/LearnNet/PNorth.gif'
elif angle == 180:
picpath = 'C:/Desktop/LearnNet/PWest.gif'
else:
picpath = 'C:/Desktop/LearnNet/PSouth.gif'
return picpath
if __name__ == '__main__': Animation().mainloop()
self in python is actually syntactic sugar.
In other words, when you say self.animate(), python translates it to Animation.animate(self). That's why you define the class methods with that "self" argument -- it's passed implicitly.
self.canv.update_idletasks(self) is evaluating to something like Canvas.update_idletasks(self.canv, self).
I found a solution by looking at some similar code. self.canv.get_tk_widgets().update_idletasks() does the trick, thought I am not quite sure WHY this works, If anyone could explain or point me to some reading. Thanks