'graphics.py and python - looking for help on button clicking - bound motion
I am working on a couple ideas here:
- hovering over a button changes the colour (using cursor binding) - works fine
- when clicked, the button changes colour - issues with this
If the user is hovering over the button, the button changes colour. The first time it works, and then if the user click anywhere OUTSIDE of the button, the button changes colour. Any ideas?
from graphics import *
win = GraphWin("button", 500, 500)
win.master.attributes('-topmost', True)
def motion(event):
x1, y1 = event.x, event.y
if (x1 > 10 and x1 < 80) and (y1 > 20 and y1 < 80):
rectangle1.setFill("red")
if win.getMouse():
rectangle1.setFill("blue")
print("Clicked")
else:
rectangle1.setFill("white")
win.bind('<Motion>', motion)
rectangle1 = Rectangle(Point(10, 20), Point(80, 80))
rectangle1.draw(win)
win.mainloop()
EDIT : I found a slight workaround, but it is doesn't feel like it is workable for a game or even menu. It works as long as the mouse is completely still when you click on it. As I said, I am sure there are ways to make this better so any help is appreciated.
from graphics import *
import time
win = GraphWin("buttons", 500, 500)
win.master.attributes('-topmost', True)
def motion(event):
x1, y1 = event.x, event.y
if (x1 > 10 and x1 < 80) and (y1 > 20 and y1 < 80):
rectangle1.setFill("red")
else:
rectangle1.setFill("white")
click = win.getMouse()
if (click.getX()>10 and click.getX()<80) and (click.getY()>20 and click.getY()<80):
rectangle1.setFill("blue")
print("Clicked")
win.bind('<Motion>', motion)
rectangle1 = Rectangle(Point(10, 20), Point(80, 80))
rectangle1.draw(win)
win.mainloop()
Solution 1:[1]
In motion I would use use global variable
global hovered
hovered = (10 < x1 < 80) and (20 < y1 < 80)
And I would use <Button-1> to run function when mouse (left-button) was clicked. And it would check if hovered is True
from graphics import *
# --- functions ---
def motion(event):
global hovered
hovered = (10 < event.x < 80) and (20 < event.y < 80)
if hovered:
rectangle1.setFill("red")
print("Hovered")
else:
rectangle1.setFill("white")
print("UnHovered")
def click_left_button(event):
if hovered:
rectangle1.setFill("blue")
print("Clicked Left")
def click_right_button(event):
if hovered:
rectangle1.setFill("black")
print("Clicked Right")
# --- main ---
hovered = False
win = GraphWin("buttons", 500, 500)
#win.master.attributes('-topmost', True)
win.bind('<Motion>', motion)
win.bind('<Button-1>', click_left_button)
#win.bind('<Button-2>', click_middle_button)
win.bind('<Button-3>', click_right_button)
rectangle1 = Rectangle(Point(10, 20), Point(80, 80))
rectangle1.draw(win)
win.mainloop()
But I don't know if this resolve all problems. Because when you keep press button then it sets BLUE but if I move then change color to RED but it should keep this color until I release button. It may need to use <ButtonPress-1> and <ButtonRelease-1>
EDIT:
it seems this works like real button
from graphics import *
# --- functions ---
def motion(event):
global previous
global hovered
hovered = (10 < event.x < 80) and (20 < event.y < 80)
if not clicked:
if hovered:
if not previous:
rectangle1.setFill("red")
print("Enter")
else:
if previous:
rectangle1.setFill("white")
print("Leave")
previous = hovered
def press_left_button(event):
global clicked
if hovered:
clicked = True
rectangle1.setFill("blue")
print("Pressed Left")
def release_left_button(event):
global clicked
if clicked:
clicked = False
print("Released left")
if hovered:
rectangle1.setFill("red")
else:
rectangle1.setFill("white")
# --- main ---
previous = False
hovered = False
clicked = False
win = GraphWin("buttons", 500, 500)
#win.master.attributes('-topmost', True)
win.bind('<Motion>', motion)
win.bind('<ButtonPress-1>', press_left_button)
win.bind('<ButtonRelease-1>', release_left_button)
rectangle1 = Rectangle(Point(10, 20), Point(80, 80))
rectangle1.setFill("white")
rectangle1.draw(win)
win.mainloop()
EDIT:
If I put code in class Button then I can simply create many buttons
from graphics import *
# --- classes ---
class Button():
def __init__(self, x, y, w, h):
self.x1 = x
self.y1 = y
self.x2 = x + w
self.y2 = y + w
self.w = w
self.h = h
self.rectangle = Rectangle(Point(x, y), Point(x+w, y+h))
self.rectangle.setFill("white")
self.previous = False
self.hovered = False
self.clicked = False
def draw(self, win):
self.rectangle.draw(win)
def on_motion(self, event):
self.hovered = (self.x1 < event.x < self.x2) and (self.y1 < event.y < self.y2)
if not self.clicked:
if self.hovered:
if not self.previous:
self.rectangle.setFill("red")
#print("Enter")
else:
if self.previous:
self.rectangle.setFill("white")
#print("Leave")
self.previous = self.hovered
def on_press_left_button(self, event):
self.clicked
if self.hovered:
self.clicked = True
self.rectangle.setFill("blue")
#print("Pressed Left")
def on_release_left_button(self, event):
self.clicked
if self.clicked:
self.clicked = False
#print("Released left")
if self.hovered:
self.rectangle.setFill("red")
else:
self.rectangle.setFill("white")
# --- functions ---
def motion(event):
for button in all_buttons:
button.on_motion(event)
def press_left_button(event):
for button in all_buttons:
button.on_press_left_button(event)
def release_left_button(event):
for button in all_buttons:
button.on_release_left_button(event)
# --- main ---
win = GraphWin("buttons", 500, 500)
#win.master.attributes('-topmost', True)
win.bind('<Motion>', motion)
win.bind('<ButtonPress-1>', press_left_button)
win.bind('<ButtonRelease-1>', release_left_button)
all_buttons = []
for y in range(10, 400, 60):
for x in range(10, 400, 60):
button = Button(x, y, 50, 50)
button.draw(win)
all_buttons.append( button )
win.mainloop()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |

