python pyglet on_mouse_press - python

I'm trying to make a simple GUI using pyglet.
Here is my code:
button_texture = pyglet.image.load('button.png')
button = pyglet.sprite.Sprite(button_texture, x=135, y=window.height-65)
def on_mouse_press(x, y, button, modifiers):
if x > button and x < (button + button_texture.width):
if y > button and y < (button + button_texture.height):
run_program()
The problem
The "button.png" is displayed as the red box with "Click" inside. and is supposed to start run_program(). But currently the yellow in the bottom left is the place i have to click to initiate run_program().

You are comparing the button (the key-code) with the X/Y coordinates. This happens, because the function parameter button shadows your global variable. Also, you should use the buttons x, y, width and height attributes.
button_texture = pyglet.image.load('button.png')
button_sprite = pyglet.sprite.Sprite(button_texture, x=135, y=window.height-65)
def on_mouse_press(x, y, button, modifiers):
if x > button_sprite.x and x < (button_sprite.x + button_sprite.width):
if y > button_sprite.y and y < (button_sprite.y + button_sprite.height):
run_program()
I renamed your global variable button with button_sprite to avoid the name collision.

Related

How to draw a square on canvas when he user clicks 2 locations with tkinter

I am writing an app where the user can "paint" a canvas and now I want to add support for shapes.
I have a canvas called paint_canvas and I want to draw a shape between the 2 points the user clicks
def draw_square(event):
x1 = event.x
y1 = event.y
# now I want to get the next two points the user clicks
# how???????
paint_canvas = Canvas(root)
paint_canvas.bind('<Button-3>', draw_square)
You can make two events,
One for the press event ans one for release.
In the first event you store x and y mouse position in another scope (startx , starty)
And in the second event you store mouse position store x and y mouse position in another scope (endx, endy) and then draw your shape with this coordinates
See : https://docstore.mik.ua/orelly/other/python/0596001886_pythonian-chp-16-sect-9.html
And : https://www.codegrepper.com/code-examples/delphi/how+to+draw+rectangle+in+tkinter
If you want to show your rect animation you can use Motion events
Mouse Position Python Tkinter
You don't have to work with double-events. You can just as well store the previously clicked coordinates and draw a rectangle (and reset the previously stored coordinates) as soon as you have two clicks:
from tkinter import *
def draw_square(event):
x1 = event.x
y1 = event.y
w = event.widget ## Get the canvas object you clicked on
if w.coords == None:
w.coords = (x1,y1)
else:
w.create_rectangle(w.coords[0],w.coords[1],x1,y1,fill="#ff0000")
w.coords = None
root = Tk()
paint_canvas = Canvas(root,width=400,height=400,bg="#ffffff")
paint_canvas.pack()
paint_canvas.bind('<Button-3>', draw_square)
paint_canvas.coords=None
root.mainloop()
You could even create a temporary point to mark the first click, which may then be removed as soon as you hit the second one. This point (w.temp in the example below) can also be an attribute of the canvas, so you can access it easily via the click:
def draw_square(event):
x1 = event.x
y1 = event.y
w = event.widget ## Get the canvas object you clicked on
if w.coords == None:
w.coords = (x1,y1)
w.temp = w.create_oval(x1-1,y1-1,x1+1,y1+1,fill="#00ff00")
else:
w.create_rectangle(w.coords[0],w.coords[1],x1,y1,fill="#ff0000")
w.delete(w.temp)
w.coords = None

python - How to recognize images and click on them

I would like to make a script that clicks on images depending on what is asked, it needs to go trough a list of images. so for example if the user is asked by the program to click on the green circle:
question_list = greencircle, redcircle, bluesquare, redtriangle
if(greencircle == greencircle.png){
pyautogui.click(greencircle.png)
}
could someone help with this?
PyAutoGUI has a built in function called locateOnScreen() which returns the x, y coordinates of the center of the image if it can find it on the current screen (it takes a screenshot and then analyzes it).
The image has to match exactly for this to work; i.e. if you want to click on a button.png that button picture has to be the same exact size / resolution as the button in your windows for the program to recognize it. One way to achieve this is to take a screenshot, open it in paint and cut out only the button you want pressed (or you could have PyAutoGUI do it for you as I'll show in a later example).
import pyautogui
question_list = ['greencircle', 'redcircle', 'bluesquare', 'redtriangle']
user_input = input('Where should I click? ')
while user_input not in question_list:
print('Incorrect input, available options: greencircle, redcircle, bluesquare, redtriangle')
user_input = input('Where should I click?')
location = pyautogui.locateOnScreen(user_input + '.png')
pyautogui.click(location)
The above example requires you to already have greencircle.png and all the other .png in your directory
PyAutoGUI can also take screenshots and you can specify which region of the screen to take the shot pyautogui.screenshot(region=(0, 0, 0, 0)) The first two values are the x,y coordinates for the top left of the region you want to select, the third is how far to the right(x) and the fourth is how far down (y).
This following example takes a screenshot of the Windows 10 Logo, saves it to a file, and then clicks on the logo by using the specified .png file
import pyautogui
pyautogui.screenshot('win10_logo.png', region=(0, 1041, 50, 39))
location = pyautogui.locateOnScreen('win10_logo.png')
pyautogui.click(location)
You also don't have to save the screenshot to a file, you can just save it as a variable
import pyautogui
win10 = pyautogui.screenshot(region=(0, 1041, 50, 39))
location = pyautogui.locateOnScreen(win10)
pyautogui.click(location)
Making a program detect if a user has clicked in a certain area (let's say, the windows 10 logo) would require another library like pynput.
from pynput.mouse import Listener
def on_click(x, y, button, pressed):
if 0 < x < 50 and 1080 > y > 1041 and str(button) == 'Button.left' and pressed:
print('You clicked on Windows 10 Logo')
return False # get rid of return statement if you want a continuous loop
with Listener(on_click=on_click) as listener:
listener.join()
PUTTING IT ALL TOGETHER
import pyautogui
from pynput.mouse import Listener
win10 = pyautogui.screenshot(region=(0, 1041, 50, 39))
location = pyautogui.locateOnScreen(win10)
# location[0] is the top left x coord
# location[1] is the top left y coord
# location[2] is the distance from left x coord to right x coord
# location[3] is the distance from top y coord to bottom y coord
x_boundary_left = location[0]
y_boundary_top = location[1]
x_boundary_right = location[0] + location[2]
y_boundary_bottom = location[1] + location[3]
def on_click(x, y, button, pressed):
if x_boundary_left < x < x_boundary_right and y_boundary_bottom > y > y_boundary_top and str(button) == 'Button.left' and pressed:
print('You clicked on Windows 10 Logo')
return False # get rid of return statement if you want a continuous loop
with Listener(on_click=on_click) as listener:
listener.join()

How to add a back button in pygame

So I decided to make a back button for by game in pygame because it has a main menu and lots of other menus within it(such as a help menu). I already have the code for making a button, but all I need is some kind of function that allows the button function like a back button.
Here is my button function that I normally use to make a button:
def button(x, y, w, h, inactive, active, action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + w > mouse[0] > x and y + h > mouse[1] > y:
gameDisplay.blit(active, (x, y))
if click[0] == 1 and action is not None:
action()
else:
gameDisplay.blit(inactive, (x, y))
Here's what each parameter in button() means:
x: x-coordinate of the button
y: y-coordinate of the button
w: width of button image
h: height of button image
active: picture of button when the mouse is hovering over it
inactive: picture of button when it is idle
action: the function to be executed when the button is clicked(this should be a function)
Thanks in advance!
What I really recommend is the pygame-menu package for creating menu. It has quite a big variety of widgets and working workflow. Probably based on their github you might find what you are looking for.
pygame-menu github
I don't understand what is the difference between yours 'back button' and 'normal button', but this page might help.
If you mean a back button which lets you get back to the main menu then you just need to reference the main menu function as the action:
backButton = button(x, y, w, h, inactive, active, mainMenu()):

python tkinter - track and save mousecklicks to build canvas items

I programmed a method like this on a canvas:
When I press button1, the variable "state" changes to 0 and every click on the canvas results in a circle
When I press button2, the variable "state" changes to 1. When the item that I clicked is a circle, my variable "selected" changes from None to 1 and I am also saving the coordinates of my mouseclick
My question: how do I code, that python should wait for the second click, and look if its another circle too? And if so, how can I draw a line between them?
def newKnotornewEdge(event):
if self.state == 0:
self.canvas.create_oval(event.x-25,event.y-25,event.x+25, event.y+25, fill="blue")
self.canvas.create_text(event.x, event.y, text="A", fill="white")
elif self.state == 1:
if self.canvas.itemcget(self.canvas.find_overlapping(event.x, event.y, event.x, event.y), "fill") == "blue":
self.selected = 1
start_x = event.x
start_y = event.y
else:
self.selected = None
if self.selected == 1 and #second mouseclick is a circle too:
#draw line that connects those circels
self.canvas.bind("<Button -1>", newKnotornewEdge)
The following canvas screenshot shows the app with 8 circles drawn; 2 and 4 of them are joined with lines; the red circle has been selected (this is what the color red indicates), and is ready to be joined to another circle, on the next click; one circle is not joined and not selected.
make_circle:
a click on the button selects the action 'draw a circle', and purges the circles that may have already been selected.
when this action is active, a click on the canvas draws a blue circle.
join_circles:
When clicked, it activates the action 'join circle' and purges the circles that may have already been selected.
The first click on a circle on the canvas selects this circle whose color changes to red; the second click on a circle on canvas selects the second circle, joins the two with a line, resets the colors to blue, and purges the selection.
A click on an empty part of the canvas does nothing.
You will need to keep track of which action to perform: draw a new circle, or select two circles to join. You also need to keep track of how many circles have been selected.
Then, after successfully drawing a line between circles, you will need to purge the selection.
I chose to use the "functions as a first class object" capability of python to avoid messy state accounting: you select the action to be performed by clicking the relevant button, then, clicks on the canvas will be related to this action.
The following code does that on the canvas, and prints which action is selected, and which is performed in the console:
import tkinter as tk
class CommandButtons(tk.Frame):
def __init__(self, master):
self.master = master
super().__init__(self.master)
self.make_circle_btn = tk.Button(root, text='make_circle', command=make_circle)
self.make_circle_btn.pack()
self.join_circles_btn = tk.Button(root, text='join_circles', command=select_circles)
self.join_circles_btn.pack()
self.pack()
class CircleApp(tk.Frame):
def __init__(self, master):
self.master = master
super().__init__(self.master)
self.canvas = tk.Canvas(root, width=600, height=600, bg='cyan')
self.canvas.pack(expand=True, fill=tk.BOTH)
self.pack()
def make_circle():
_purge_selection()
print('cmd make_circle selected')
c_app.canvas.bind('<Button-1>', _make_circle)
def _make_circle(event):
c_app.canvas.create_oval(event.x - 25, event.y - 25, event.x + 25, event.y + 25, fill="blue")
def select_circles():
_purge_selection()
print('cmd join_circles selected')
c_app.canvas.bind('<Button-1>', _select_circles)
def _select_circles(event):
print(f'select circle {event}')
x, y = event.x, event.y
selection = c_app.canvas.find_overlapping(x, y, x, y)
if selection is not None and len(selected_circles) < 2:
selected_circles.append(selection)
c_app.canvas.itemconfigure(selection, fill='red')
if len(selected_circles) == 2:
if all(selected_circles):
_join_circles()
_purge_selection()
def _join_circles():
coordinates = []
for item in selected_circles:
x, y = find_center(item)
print(x, y)
coordinates.append(x)
coordinates.append(y)
c_app.canvas.create_line(coordinates)
def _purge_selection():
global selected_circles
for item in selected_circles:
c_app.canvas.itemconfigure(item, fill='blue')
selected_circles = []
def find_center(item):
x0, y0, x1, y1 = c_app.canvas.bbox(item)
return (x0 + x1) / 2, (y0 + y1) / 2
if __name__ == '__main__':
selected_circles = []
root = tk.Tk()
command_frame = CommandButtons(root)
c_app = CircleApp(root)
root.mainloop()
A better version would use a class to encapsulate the selected items; here I used a collection as global variable. It would also properly handle overlapping circle selection.

wxPython Binding Problem

I'm playing with wxPython event bindings in order to make a dragging algorithm. However I've encountered a problem, when the mouse is not directly over my frame the event doesn't trigger.
This becomes a problem while dragging seeing as if the mouse escapes the frame (like if the user moved it quickly), the frame neglects to update it's position.
Is there anyway to change the bindings so that they trigger even if the mouse isn't over the frame in question?
Snippet:
self.Bind(wx.EVT_LEFT_DOWN, self.relative_mouse_position)
self.Bind(wx.EVT_LEFT_UP, self.wid_unbind)
Snippet:
def relative_mouse_position (self, event):
cx, cy = wx.GetMousePosition()
x, y = self.GetPosition()
RelX = cx - x
RelY = cy - y
self.Bind(wx.EVT_MOTION, lambda event: self.wid_drag(event, RelX, RelY))
def wid_drag (self, event, RelX, RelY):
cx, cy = wx.GetMousePosition()
x = cx - RelX
y = cy - RelY
if x < 0:
x = 0
if y < 0:
y = 0
self.SetPosition((x, y))
def wid_unbind (self, event):
self.Unbind(wx.EVT_MOTION)
When you start a drag, call CaptureMouse to keep the mouse locked to the window that you're dragging.
Not tested but probably bind, EVT_LEAVE_WINDOW to trigger when mouse is outside window.

Categories