I have come up with some code that I am using for a clicker game, kinda like Cookie Clicker.
from tkinter import *
import time
master = Tk()
def uiPrint():
info()
print("")
print(click)
blankLine()
def info():
print("Double click purchases need 50 clicks!")
print("Auto clicker purchases need 75 clicks!")
info()
click = 0
mult = 1
dcp1 = 0
def blankLine():
for i in range(20):
print("")
def purchaseDoubleClicksCommand():
global click
global mult
if click < 5:
print("Not enough clicks!")
blankLine()
elif click >= 5:
mult = mult*2
click = click - 5
print("Double Clicks Purchased!")
blankLine()
def purchaseAutoClickerCommand():
global click
if click < 7:
print("Not enough clicks!")
blankLine()
elif click >= 7:
click = click - 7
print("Auto clicker purchased!")
while True:
click = click + 1
time.sleep(1)
def buttonCommand():
global click
global mult
click += 1*(mult)
uiPrint()
if click == 100:
print('''Achievement Unlocked: Junior Clicker!
BONUS 100 clicks!''')
click += 100
elif click == 400:
print ('''Achievement Unlocked: Little Ninja Clicks!
BONUS 200!''')
click += 300
elif click == 1500:
print ('''Achievement Unlocked: Click Ninja Master!
QUAD CLICKS!''')
mult = mult * 4
elif click == 3000:
print ('''Achievement Unlocked: Jackie Chan Style!
8 TIMES THE CLICKS!''')
mult = mult * 8
mainClickButton = Button(master, text="Click!", command = buttonCommand)
mainClickButton.pack()
purchaseDoubleClickButton = Button(master, text="Purchase Double Clicks", command = purchaseDoubleClicksCommand)
purchaseDoubleClickButton.pack()
purchaseAutoClickerButton = Button(master, text="Purchase Auto Clicker", command = purchaseAutoClickerCommand)
purchaseAutoClickerButton.pack()
master.title("Clicker! v0.0.6")
master.geometry("%sx%s+%s+%s" % (200,70,512,512))
mainloop()
This is the code that I have so far. I am trying to add an Auto Clicker that you can buy through a button. I have found one other post that is about this, but the solution for that uses PyMouse which 1.) I can't get installed (Trust me I've tried everything) and 2.) Don't want to imitate user input.
So this is the code in question.
def purchaseAutoClickerCommand():
global click
if click < 7:
print("Not enough clicks!")
blankLine()
elif click >= 7:
click = click - 7
print("Auto clicker purchased!")
while True:
click = click + 1
time.sleep(1)
And the code in charge of the button
purchaseAutoClickerButton = Button(master, text="Purchase Auto Clicker", command = purchaseAutoClickerCommand)
purchaseAutoClickerButton.pack()
When I hit the button that says "Purchase Auto Clicker", not only do I not get the number of clicks to increase by one per second, but the entire app crashes.
So my main question is, how can I have the number of clicks increase by one per second by the game itself (without the user needing to keep the mouse on the "Click!" button), and how can I have the Auto Clickers stack when more than one are bought (plus I would like to not have the program crash as soon as I try to buy it).
Editing this for Scratso to see:
This is what I have changed to the code
click = 0
mult = 1
dcp1 = 0
autoclickers = 0
def blankLine():
for i in range(20):
print("")
def purchaseDoubleClicksCommand():
global click
global mult
if click < 5:
print("Not enough clicks!")
blankLine()
elif click >= 5:
mult = mult*2
click = click - 5
print("Double Clicks Purchased!")
blankLine()
def purchaseAutoClickerCommand():
global click
global autoclickers
if click < 7:
print("Not enough clicks!")
blankLine()
elif click >= 7:
autoclickers += 1 # add an autoclicker
click = click - 7
print("Auto clicker purchased!")
And at the end of the code I have added
while True:
mainClickButton = Button(master, text="Click!", command = buttonCommand)
mainClickButton.pack()
purchaseDoubleClickButton = Button(master, text="Purchase Double Clicks", command = purchaseDoubleClicksCommand)
purchaseDoubleClickButton.pack()
purchaseAutoClickerButton = Button(master, text="Purchase Auto Clicker", command = purchaseAutoClickerCommand)
purchaseAutoClickerButton.pack()
master.title("Clicker! v0.0.6")
master.geometry("%sx%s+%s+%s" % (200,70,512,512))
mainloop()
for autoclicker in range(autoclickers):
click += 1
time.sleep(1)
The problem with using sleep() in a tkinter application is that it messes with the way the GUI is updated. Instead, call after() on the root tkinter object to tell it to execute the given command (function) after the given number of milliseconds have elapsed. This after() call will be placed within the function itself, so that, after calling this function normally, it will be called again one second later.
autoclickers=0 # start autoclickers at 0
def purchaseAutoClickerCommand():
global click
global autoclickers # declare global
if click < 7:
print("Not enough clicks!")
blankLine()
else:
click -= 7 # pay for an autoclicker
print("Auto clicker purchased!")
autoclickers += 1 # receive an autoclicker
def autoclick():
global master
global click
global autoclickers
click += autoclickers # get clicks from autoclickers
master.after(1000, autoclick) # do this again 1 second later
autoclick() # start benefiting from all existing autoclickers
well, I noticed that using time will just lag everything. Try using timers or make it add .00001 clicks so it will make it kinda like a timer.
What I would recommend for just the clicking is just using a module like pyautogui or something which can type keys and click on its own, unless you were asking for like a autoclicker but you can click on the side
EDIT
you could use a while loop which adds 1 per second
I downloaded an autoclicker my self and after 5 seconds of holding my mouse over the click button and ten over the double button i achieved this amount of clicks. (copy, paste)
755556783768937868934768457868378674578897653689974322127907543098763683978387683767937784870388737657475555678376893786893476845786837867457889765368997432212790754309876368397838768376793778487038873765747555567837689378689347684578683786745788976536899743221279075430987636839783876837679377848703887376574755556783768937868934768457868378674578897653689974322127907543098763688934768457868378674578897653689974322127907543098763683978387683767937784870388737657475555678376893786893476445533384578683786745788976536899743221279075430987636839783876837679377848703887376574755556783768937868934224457684578683786745788976536899743221279075430987636839783876837679377848703887376574755556783768937868934768457868378674578897653689974322127907543098763683978387683767937784870388737657475555678376893786893476845786837867457889765368997432212790754309876366666666664344667645544448397838768376793778487038873765747555567837689378689347684578683786745788976536899743221279075430987636839783876837679377848703887333765747555567837689378689347684578683786745788976536899743221279075430987636839783876837679377848703887376574755556783768937868934768457868378674578897653689974322127907543098783978383333368376793778487038873765747555567837689378689347684578683786745788976536899743221279075430987636839783876837679377848703887376574755556783768937868934768457868378674578897653689974322127907543098763683978387683767937784870388737657475555678376893786893476845786837867457889765666536899743221279075430987636839783876837679377848703887376574755556783768937868934768457868378674578897653689974322127907543098763683978387683767937784870388737657475555678376893786893476845786837867457889765368997432212790754309876368397838768376793778487038873765747555567837689378689347684578683786745788976536899743221279075430987636839783876837679377848703887376574755556783768937868934768457868378674578897653689974322127907543098763683978387683767937784870388737657475555678376893786893476845786837867457889765368997432212790754309876368397838768376793778487038873765747555567837689378689347684578683786745788976536899743221279075430987636839783876837679377848703887376574
Related
I'm trying to count button click but only after 5 clicks and after the fifth click it will print the clicks BUT starting at 1.
Example:
Press button = 1 click
Press button = 2 click
Press button = 3 click
Press button = 4 click
Press button = 5 click
Press button = "ROUND: 1"
Press button = "ROUND: 2"........etc.
I have the function below and when button_clicks() is called it displays and counts a 6,7,8 etc. instead 1,2,3 etc.
clicks = 0
def button_clicks():
global clicks
clicks += 1
if (clicks) > 5:
lcd.move_to(0,3) #Moves text 0 characters from left on row 4
lcd.putstr("ROUND: " + str(clicks))
I also needed to add another two buttons B3 and B4 that would decrease or increase the number by 1. How would I do that?
I figured it out.... But still need a button to increase and a button to decrease the value.
def button_clicks():
global clicks
clicks += 1
if (clicks) > 5:
lcd.move_to(0,3) #Moves text 0 characters from left on row 4
lcd.putstr('Rnds: {}'.format(clicks-5))
else:
lcd.move_to(0,3) #Moves text 0 characters from left on row 4
lcd.putstr('Rnds: -{}'.format(clicks))
I had another question open about iterative menu logic, and the problem morphed into button logic, so I'm separating them, since the original question was truly settled.
My code is as follows:
""" fit: a productivity logger """
import time
import sys
import os
import uhashlib
import machine
import framebuf
from ssd1306 import SSD1306_I2C
def final_print(sec,final_hash,final_survey):
""" leaves the summary on the screen before shutting down """
mins = sec // 60
sec = sec % 60
hours = mins // 60
mins = mins % 60
short_sec = int(sec)
duration = (str(hours) + "/" + str(mins) + "/" + str(short_sec))
oled_show("> fit the"+str(final_hash),str(final_survey),"//"+str(duration))
time.sleep(30)
oled_blank()
def timer_down(f_seconds,timer_focus):
""" counts down for defined period """
now = time.time()
end = now + f_seconds
while now < end:
now = time.time()
fit_progress(now,end,timer_focus,f_seconds)
time.sleep(0.01)
# if button1.value() == 0:
# oled_show("","Ended Manually!","")
# time.sleep(2)
# break
def timer_up(timer_focus):
""" counts up for indefinite period """
now = time.time()
while True:
minutes = int((time.time() - now) / 60)
oled_show(str(timer_focus)," for ",str(minutes))
time.sleep(0.01)
# if button1.value() == 0:
# oled_show("","Ended Manually!","")
# time.sleep(2)
# break
def fit_progress(now,end,timer_focus,f_seconds):
""" tracks progress of a count-down fit and prints to screen """
remain = end - now
f_minutes = int((remain)/60)
j = 1 - (remain / f_seconds)
pct = int(100*j)
oled_show(str(timer_focus),str(f_minutes)+" min",str(pct)+"%")
def debounce(btn):
""" some debounce control """
count = 2
while count > 0:
if btn.value():
count = 2
else:
count -= 1
time.sleep(0.01)
def multi_choice(options):
""" provides multi-choice menus for two-button navigation """
for i in options:
oled_show("> fit",i,"1:yes 2:next")
# Wait for any button press.
while 1:
b1pressed = button1.value()
b2pressed = button2.value()
if b1pressed or b2pressed:
break
if b1pressed:
print( i, "chosen" )
debounce(button1)
return i
# We know B2 was pressed.
debounce(button2)
def oled_show(message1,message2,message3):
""" displays a three line message """
oled.fill(0) # clear the display
oled.text(message1,5,5)
oled.text(message2,5,15)
oled.text(message3,5,25)
oled.show()
def oled_blank():
""" blanks the oled display to avoid burn in """
oled.fill(0)
oled.show()
sda = machine.Pin(4)
scl = machine.Pin(5)
i2c = machine.I2C(0,sda=sda, scl=scl, freq=400000)
oled = SSD1306_I2C(128, 32, i2c)
button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)
F_TYPE = multi_choice(['30-minute fit','60-minute fit','indefinite fit'])
F_FOCUS = multi_choice(['personal fit','work fit','learn fit','admin fit'])
fStart = time.time()
if F_TYPE == "30-minute fit":
timer_down(1800,F_FOCUS)
elif F_TYPE == "60-minute fit":
timer_down(3600,F_FOCUS)
elif F_TYPE == "indefinite fit":
timer_up(F_FOCUS)
else:
sys.exit()
fEnd = time.time()
F_SURVEY = multi_choice(['went well','went ok','went poorly'])
fDuration = fEnd - fStart
F_HASH = uhashlib.sha256(str(fEnd).encode('utf-8')).digest()
F_HASH_SHORT = F_HASH[0:3]
fitdb = open("data.csv","a")
fitdb.write(str(F_HASH)+","+str(F_TYPE)+","+str(F_FOCUS)+","+str(F_SURVEY)+","+str(fStart)+","+str(fEnd)+","+str(fDuration)+"\n")
fitdb.close()
final_print(fDuration,F_HASH_SHORT,F_SURVEY)
In particular, you can see that I have two buttons defined:
button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)
And they are primarily used to select from menus with multiple choices:
def debounce(btn):
""" some debounce control """
count = 2
while count > 0:
if btn.value():
count = 2
else:
count -= 1
time.sleep(0.01)
def multi_choice(options):
""" provides multi-choice menus for two-button navigation """
for i in options:
oled_show("> fit",i,"1:yes 2:next")
# Wait for any button press.
while 1:
b1pressed = button1.value()
b2pressed = button2.value()
if b1pressed or b2pressed:
break
if b1pressed:
print( i, "chosen" )
debounce(button1)
return i
# We know B2 was pressed.
debounce(button2)
However, I am encountering an issue whereby the buttons can only be pressed alternately. That is, when the multi_choice function begins, I can press button1 to select the first option, or I can press button2 to scroll to the next option, but, if I press button2, for example, it will not register for a second press (to select a second option), I can only then press button1... if I do that, I can only then press button2 next.
I'm certain this is just a logic issue I'm not seeing.
The buttons are ordinary momentary-closed Cherry MX switches on GPIO pins 2 and 3. They definitely work reliably, but something about this logic is wonky.
The following test works just fine, so it's not the buttons...
import machine
import time
button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)
while True:
b1pressed = button1.value()
b2pressed = button2.value()
time.sleep(0.01)
b1released = button1.value()
b2released = button2.value()
if b1pressed and not b1released:
print('Button1 pressed!')
if b2pressed and not b2released:
print('Button2 pressed!')
if not b2pressed and b2released:
print('Button2 released!')
elif not b1pressed and b1released:
print('Button1 released!')
I added in some print statements to debug this, and I can see the buttons taking and holding values. I feel like I need to tune in an artificial reset, maybe that's something I can do in debounce? I tried a few things, but I'm not making progress so far.
def debounce(btn):
""" some debounce control """
count = 2
while count > 0:
if btn.value():
count = 2
else:
count -= 1
time.sleep(0.01)
def multi_choice(options):
""" provides multi-choice menus for two-button navigation """
for i in options:
print("below for")
print("button 1 below for",button1.value())
print("button 2 below for",button2.value())
oled_show(" fit",i,"1:sel 2:next")
while 1:
print("below while")
print("button 1 below while",button1.value())
print("button 2 below while",button2.value())
b1pressed = button1.value()
b2pressed = button2.value()
if b1pressed or b2pressed:
print("below first if")
print("button 1 first if",button1.value())
print("button 2 first if",button2.value())
break
if b1pressed:
print("below second if")
print("button 1 second if",button1.value())
print("button 2 second if",button2.value())
debounce(button1)
return i
debounce(button2)
and the output of the above debug prints:
>>> %Run -c $EDITOR_CONTENT
below for
button 1 below for 0
button 2 below for 1
below while
button 1 below while 0
button 2 below while 1
below first if
button 1 first if 0
button 2 first if 1
below for
button 1 below for 1
button 2 below for 0
below while
button 1 below while 1
button 2 below while 0
below first if
button 1 first if 1
button 2 first if 0
below second if
button 1 second if 1
button 2 second if 0
below for
button 1 below for 0
button 2 below for 1
below while
button 1 below while 0
button 2 below while 1
below first if
button 1 first if 0
button 2 first if 1
below for
button 1 below for 1
button 2 below for 0
below while
button 1 below while 1
button 2 below while 0
below first if
button 1 first if 1
button 2 first if 0
below second if
button 1 second if 1
button 2 second if 0
With both of your buttons tied to ground, and using PULL_UP the code is just:
import machine
button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)
while True:
print('Button1 down!') if not button1.value() else print('Button1 up!')
print('Button2 down!') if not button2.value() else print('Button2 up!')
The logic is simple. Your button is tied to ground on one end and pulled up on the other. When you press that button it's going to connect the pin of the MCU to ground. When the button is pressed value() will be zero, and when it is released value() will be one. If you want value() to be positive when you press the button then you need to tie the button to the Vcc rail and use PULL_DOWN on the MCU pin.
All that debouncing code probably isn't even necessary, and even if it was necessary creating a loop to handle it isn't the answer. What if your button doesn't bounce ~ now you're just stuck in a loop. Get a 74HC14 or make a simple RC network if you're worried about bouncing. Assigning all these arbitrary values to button states and sticking buttons in loops that block your other buttons is just a bunch of noise. It's very simple: You have one question that you want to ask twice. "Is this button pressed" ~ so just "ask" that question twice and move on. It doesn't take 20 lines of code to determine if something is 1 or 0.
Aside:
You do not have a separate "GND". All your "GND" pins are connected to the same "GND". You have one power source right? Well, one is one. Cutting a cake into 8 pieces doesn't give you 8 cakes.
Ok, with the help from everybody here, I figured this out. Just needed to add a little sleep to avoid spill-over of the keypress from the previous while loop.
def multi_choice(options):
""" provides multi-choice menus for two-button navigation """
for i in options:
oled_show(" fit",i,"1:sel 2:next")
time.sleep(0.5)
while 1:
if not button1.value():
return i
if not button2.value():
break
Thanks all!
I got the source code of a timer that synchronizes with the timer of a videogame bomb but the problem is, when I'm playing the game and move my mouse and click it, I accidentally click the Timer UI and it makes the command prompt where the script is running pop up and it's really gamebreaking.
I was wondering if there's any way to make the UI clicktrough so even if I click it accidently the application does not pop up.
Here's the UI's code:
import tkinter as tkr
from python_imagesearch.imagesearch import imagesearch
root = tkr.Tk()
root.geometry("+0+0")
root.overrideredirect(True)
root.wm_attributes("-topmost", True)
root.wm_attributes("-alpha", 0.01)
root.resizable(0, 0)
timer_display = tkr.Label(root, font=('Trebuchet MS', 30, 'bold'), bg='black')
timer_display.pack()
seconds = 44
//in this space i print a lot of lines creating a box with text explaining what the script does in it.
def countdown(time):
if time > 0:
mins, secs = divmod(time, 60)
ID = timer_display.bind('<ButtonRelease-1>', on_click)
timer_display.unbind('<ButtonRelease-1>', ID)
def color_change(t_time):
if t_time > 10:
return 'green'
elif 7 <= t_time <= 10:
return 'yellow'
elif t_time < 7:
return 'red'
timer_display.config(text="{:02d}:{:02d}".format(mins, secs),
fg=color_change(time)), root.after(1000, countdown, time - 1)
else:
root.wm_attributes('-alpha', 0.01)
search_image()
def start_countdown():
root.wm_attributes('-alpha', 0.7)
countdown(seconds)
def search_image():
pos = imagesearch("./github.png")
pos1 = imagesearch("./github1.png")
if pos[0] & pos1[0] != -1:
start_countdown()
else:
root.after(100, search_image)
root.after(100, search_image)
root.mainloop()
If the UI you are talking about is timer_display then I suppose you are using bind function for the clicking part you were talking about. Here is what you can try:
# Save the binding ID
ID = timer_display.bind('<ButtonRelease-1>', on_click)
Then use it to unbind <ButtonRelease-1>
timer_display.unbind('<ButtonRelease-1>', ID)
Maybe this question might be of some help.
I'm creating a program for my class involving creating a simple game with graphics.py by John Zelles, definitions that each function within graphics.py can do.
My game basically has a visible timer and counter that checks how many times the window has been clicked. The user is supposed to click in the window to start a 60 second timer. Then, the game will show a number telling the user the amount of times they have to click in the window in order to win the game.
If the timer runs out before the player finishes the amount of clicks, then they lose the game.
However, in my code whenever I click in the window to begin the game, the timer starts but it doesn't display the message telling me how many times I need to click in the window to win the game. It just waits for the timer to finish AND THEN it let's me click inside of the window.
'''
def main():
win = GraphWin('Test', 300, 300)
win.setBackground("green")
message = Text(Point(150, 30), "Click to start the game")
message.draw(win)
win.getMouse()
start = True
sec = 5
timer = start
secondsRemain = 5
for i in range(secondsRemain):
message.undraw()
sec -= 1
message = Text(Point(150, 30), "You have left: " + str(sec+1))
message.draw(win)
time.sleep(1)
if sec == 0:
message.undraw()
finalMessage = Text(Point(150, 30), "You LOST!")
finalMessage.draw(win)
else:
continue
clickCounter = randrange(200)
while clickCounter > 0:
clicker = Text(Point(200, 50), "Click the window " + str(clickCounter) +" times!")
clicker.draw(win)
win.getMouse()
clickCounter -= 1
clicker.undraw()
if clickCounter == 0:
eye1.undraw()
win.getMouse()
win.close()
main()
'''
I also don't want to import any more libraries (if possible). I want to use mostly and only the graphics.py file. And thank you!
I can see a couple of little fixes on this one. By using time.sleep(1) you're essentially causing the script to stop on that line and ignore all the other logic, and then do all the other logic very quickly skipping back to the sleep again. My solution would be to replace that by continuously checking the time with time.time() rather than sleep, so you don't need any other libraries, as you're already using time. Also, by having a loop exterior to another it makes it more complicated to keep a track of when lines are being called, so I replaced it with one for you. I hope this modification to the script below helps you the faster fluttering of the screen I find adds some more urgency.
# Edited by Bryce
from graphics import *
from random import *
import time
def main():
win = GraphWin('Face Hitter!', 300, 300)
win.setBackground("blue")
clickCounter = randint(50, 100) ## Adjust minimum and maximum for difficulty
message = Text(Point(150, 30), "Click to start the game")
clicker = Text(Point(200, 50), "Click the window " + str(clickCounter) +" times!")
message.draw(win)
win.getMouse()
start = True
initialTime = time.time()
secondsRemain = 60 ## A full minute
while (secondsRemain > 0):
print(secondsRemain)
secondsRemain = 60 - (time.time() - initialTime) ## Check how long has elapsed since originally checking the time
message.undraw()
message = Text(Point(150, 30), "You have left: " + str(secondsRemain))
message.draw(win)
if secondsRemain < 0:
message.undraw()
finalMessage = Text(Point(150, 30), "You LOST!")
finalMessage.draw(win)
clicker.undraw()
clicker = Text(Point(200, 50), "Click the window " + str(clickCounter) +" times!")
clicker.draw(win)
if (win.checkMouse()):
clicker.undraw()
clickCounter -= 1
if clickCounter == 0:
clicker.undraw()
clicker = Text(Point(200, 50), "YOU WON!")
clicker.draw(win)
#eye1.undraw() ## Remove the # when using it, eye1 wasn't declared in this section of the code so I could test it
print("Undraw eye - End of game")
break
print("Waiting for mouse click to quit...")
win.getMouse()
win.close()
main()
Good luck with your program Omar!
When creating a turtle onclick event my clicks lags 1 click behind.
In my example I have two buttons that adds or subtracts 1 from a value, when I click one of the buttons it does the action of the last button I pushed, not the one I just clicked.
Example:
My number is 3.
Start program.
Click "+" -> nothing happens.
Click "+" -> number becomes 4.
Click "-" -> number becomes 5.
Click somewhere blank -> number becomes 4.
Click "+" -> nothing happens.
Click somewhere blank -> number becomes 5.
Example code.
import turtle
num = 3
turtle.setup(400,500)
wn = turtle.Screen()
wn.title("None")
wn.bgcolor("black")
# Functions for what happens clicking the minus or plus button
def num_minus(xcor, ycor):
global num
if num > 1:
num = num-1
num_disp.clear()
num_disp.write("{}".format(num), align="center", font=("Arial", 26, "normal"))
print(num)
def num_plus(xcor, ycor):
global num
if num < 9:
num = num+1
num_disp.clear()
num_disp.write("{}".format(num), align="center", font=("Arial", 26, "normal"))
print(num)
# Creating minus button, left of number
minus_btn = turtle.Turtle()
minus_btn.penup()
minus_btn.color("gray")
minus_btn.shape("square")
minus_btn.goto(-30, 0)
minus_btn.onclick(num_minus)
# Creatig plus button, right of number
plus_btn = turtle.Turtle()
plus_btn.penup()
plus_btn.color("gray")
plus_btn.shape("square")
plus_btn.goto(30, 0)
plus_btn.onclick(num_plus)
# Displays the number
num_disp = turtle.Turtle()
num_disp.penup()
num_disp.color("red")
num_disp.goto(0, -20)
num_disp.write("{}".format(num), align="center", font=("Arial", 26, "normal"))
num_disp.ht()
wn.listen()
wn.mainloop()
Why are my clicks 1 click behind, and how do I fix this?
I was not able to reproduce the errant behavior you describe. Regardless, here's some possibilities to consider:
On some systems, the turtle window does not come up as the key window and you need to click on it once (anywhere) to have it receive events. You should be able to click between the turtle window and another window on your screen to see how the windows visually change as they gain, and lose, key status. If your window needs to be clicked first to receive events, then you may be miscounting that click as a button click.
Your event handlers are open to receive a new event while they are still processing a previous event. They should be disabled until they are ready for a new event to keep events from interrupting one another and messing with your count.
You instruct the turtle window to listen() to keyboard events which are not used in this interface, so don't turn that on.
Below is my rework of your code to address some of the above and restyle it -- see if it fixes any of your issues or not:
from turtle import Screen, Turtle
FONT_SIZE = 26
FONT = ('Arial', FONT_SIZE, 'normal')
number = 3
# Functions for what happens when clicking the minus or plus button
def number_minus(x, y):
global number
minus_button.onclick(None) # disable handler inside handler
if number > 1:
number -= 1
number_display.clear()
number_display.write(number, align='center', font=FONT)
minus_button.onclick(number_minus) # reenable handler on exit
def number_plus(x, y):
global number
plus_button.onclick(None)
if number < 9:
number += 1
number_display.clear()
number_display.write(number, align='center', font=FONT)
plus_button.onclick(number_plus)
screen = Screen()
screen.setup(400, 500)
screen.bgcolor('black')
# Displays the number
number_display = Turtle()
number_display.hideturtle()
number_display.color('red')
number_display.penup()
number_display.sety(-FONT_SIZE/2)
number_display.write(number, align='center', font=FONT)
# Creating minus button, left of number
minus_button = Turtle()
minus_button.shape('triangle')
minus_button.color('gray')
minus_button.left(30)
minus_button.penup()
minus_button.setx(-30)
minus_button.onclick(number_minus)
# Creatig plus button, right of number
plus_button = Turtle()
plus_button.shape('triangle')
plus_button.color('gray')
plus_button.right(30)
plus_button.penup()
plus_button.setx(30)
plus_button.onclick(number_plus)
screen.mainloop()