I am new to python and I found a code that detects mouse buttons when held down and released, but i want "x" to turn True when both of the buttons held down, how can I do this
# This function will be called when any key of mouse is pressed
def on_click(*args):
# see what argument is passed.
print(args)
if args[-1]:
# Do something when the mouse key is pressed.
print('The "{}" mouse key has held down'.format(args[-2].name))
elif not args[-1]:
# Do something when the mouse key is released.
print('The "{}" mouse key is released'.format(args[-2].name))
# Open Listener for mouse key presses
with Listener(on_click=on_click) as listener:
# Listen to the mouse key presses
listener.join()
To detect if both buttons are held down simultaneously, three variables will be required (initialise these at the start of your program, outside of the on_click function):
global leftPressed, rightPressed, bothPressed
leftPressed = False
rightPressed = False
bothPressed = False
*note the variables are global here, as multiple versions of on_click will be accessing and modifying the variables
Then, in the first if statement (when a mouse button has been pressed):
if args[-2].name == "left":
leftPressed = True
elif args[-2].name == "right":
rightPressed = True
if leftPressed and rightPressed:
# if both left and right are pressed
bothPressed = True
And in the second if statement (when a mouse button has been released)
if args[-2].name == "left":
leftPressed = False
elif args[-2].name == "right":
rightPressed = False
# as one key has been released, both are no longer pressed
bothPressed = False
print(bothPressed)
Finally, to access the global variables from within the function on_click, place this line at the start of the function:
global leftPressed, rightPressed, bothPressed
See a full version of the code here:
https://pastebin.com/nv9ddqMM
I am trying to convert from pygame to tkinter as it seems to be much better for what I want to do, although I have hit a bit of a wall. I need to be able to call a function when both a certain key and mouse button are pressed. In pygame it was as simple as the following.
while not done:
for event in pygame.event.get():
keys = pygame.key.get_pressed()
mouse = pygame.mouse.get_pressed()
if event.type == pygame.QUIT:
done = True
if mouse[0]:
if keys[pygame.K_s]:
pos = pygame.mouse.get_pos()
// function
I know in tkinter you can do c.bind("<Button-1>", function) to register mouse clicks and c.bind("e", function) to register key presses but I'm not sure how to get both at the same time as the button event does not pass through key presses
Not sure if there is an official method to bind both Button-1 and Key, but maybe you can work around it.
import tkinter as tk
root = tk.Tk()
tk.Label(root,text="Hi I'm a label").pack()
class Bindings:
def __init__(self):
self.but_1 = False
root.bind("<Button-1>", self.mouse_clicked)
root.bind("<e>", self.e_clicked)
root.bind("<ButtonRelease-1>",self.mouse_release)
def mouse_release(self,event):
self.but_1 = False
def mouse_clicked(self,event):
self.but_1 = True
print ("Mouse button 1 clicked")
def e_clicked(self,event):
if self.but_1:
print ("Both keys clicked")
self.but_1 = False
else:
print ("Key E pressed")
Bindings()
root.mainloop()
So I am writing code for a a Stealth Game in python, I am using the pygame module for it but this problem may not even concern it. I have stages for my menu where I am taking an OOP approach (I am new to OOP so please don't hate so much on my code!) where buttons are generated for a menu where there is a play and quit button. Then Easy, medium, hard and veteran buttons are loaded on top of the old buttons (where the previous buttons lose functionality) and then the 1, 2 , 3 and 4 buttons for levels are loaded again on top of the previous ones if that makes sense. However, the way I wrote my code, I need for the variable stage where stage 1 is the play and quit, 2 is the difficulty and 3 is the level number to be passed out the method and class it would need to be in. I don't know how to do this without declaring the variable with a global scope which defeats the purpose of OOP I think. So how do I? Because otherwise the code just takes input and goes through all the buttons to the end.
Here is my code, you would need images I guess of at least the text files.
#Stealth Assassin
import pygame #Imports the pygame module inclulding many in built functions that aids in game design
import time #Imports the time module for which I can implement delays into my program
pygame.init() #Runs pygame
clock = pygame.time.Clock() #Intialises the variable to control the game clock (FPS)
gameDisplay = pygame.display.set_mode((1920,1080),pygame.FULLSCREEN) #Variable which will set the resolution of the game window and put the window into fullscreen mode
pygame.display.set_caption("Stealth Assassin") #Sets the title of the pygame window for the game
class DisplayImage: #This class contains methods required to load images into the game
def __init__(self, filename, xpos, ypos): #Method used to allow the class to intialise attributes
self.filename = filename #Defines filename as the filename attribute passed through
self.xpos = xpos #Defines the x axis positioning of the image as the attribute passed through
self.ypos = ypos #Defines the y axis positioning of the image as the attribute passed through
def LoadImage(self): #This method will load images into the game displaying them
image = pygame.image.load(self.filename+".png") #Image is loaded into the program
gameDisplay.blit(image, (self.xpos,self.ypos)) #Image is displayed to coordinates which were attributes that were defined prior
stage = 1 #Sets the menu as stage 1 which is the play and quit buttons
class Button: #This class contains methods for buttons including display and functionality
def __init__(self, buttonname, buttonx, buttony, buttonwidth, buttonheight, textfile, textx, texty, stage): #Methods used to allow classes to intialise attributes
self.buttonname = buttonname #Defines the name of the button as the attribute passed through
self.buttonx = buttonx #Defines the x axis positioning of the button as the attribute passed through
self.buttony = buttony #Defines the y axis positioning of the button as the attribute passed through
self.buttonwidth = buttonwidth #Defines the width of the button as the attribute passed through
self.buttonheight = buttonheight #Defines the height of the button as the attribute passed through
self.textfile = textfile #Sets the name of the textfile to be called
self.textx = textx #Defines the x axis positioning of the text as the attribute passed through
self.texty = texty #Defines the y axis positioning of the text as the attribute passed through
self.stage = stage #Sets the stage of the menu which has 3 states of play/quit, difficulty and level choice
def createbutton(self): #Method which creates a button for the menu
buttonname = pygame.draw.rect(gameDisplay, (0,0,0), [self.buttonx, self.buttony, self.buttonwidth, self.buttonheight]) #Draws a rectangular button which is black and given the size and coordinates which were attributes
text = pygame.image.load(self.textfile+".png") #Loads the text file into the program
gameDisplay.blit(text, (self.textx,self.texty)) #Displays the text given coordinates
def quitbutton(self): #Method which quits the program if the quit button is clicked
if self.buttonx+self.buttonwidth > mouse[0] > self.buttonx and self.buttony+self.buttonheight > mouse[1] > self.buttony and pressed[0] == 1: #If the button is clicked (regarding its dimensions)
pygame.quit() #Exits pygame
quit() #Quits program
def buttonaction(self): #Method which takes action for the particular button
if self.buttonx+self.buttonwidth > mouse[0] > self.buttonx and self.buttony+self.buttonheight > mouse[1] > self.buttony and pressed[0] == 1: #If the button is clicked (regarding its dimensions)
if self.stage == 1: #If the play/quit buttons are active
EasyButton.createbutton() #Creates and displays the easy button through the button class and its method
MediumButton.createbutton() #Creates and displays the medium button through the button class and its method
HardButton.createbutton() #Creates and displays the hard button through the button class and its method
VeteranButton.createbutton() #Creates and displays the veteran button through the button class and its method
if self.stage == 2: #If the difficulty buttons are active
OneButton.createbutton() #Creates and displays the one button through the button class and its method
TwoButton.createbutton() #Creates and displays the two button through the button class and its method
ThreeButton.createbutton() #Creates and displays the three button through the button class and its method
FourButton.createbutton() #Creates and displays the four button through the button class and its method
if self.buttonname == 'easybutton':
difficulty = 'easy'
if self.buttonname == 'mediumbutton':
difficulty = 'medium'
if self.buttonname == 'hardbutton':
difficulty = 'hard'
if self.buttonname == 'veteranbutton':
difficulty = 'veteran'
print(difficulty)
time.sleep(0.5)
PlayButton = Button('playbutton',133,477,756,223,'PlayText',387,545,1) #Creates play button
QuitButton = Button('quitbutton',133,731,756,223,'QuitText',387,806,None) #Creates quit button
EasyButton = Button('easybutton',127,477,362,223,'EasyText',214,548,2) #Creates easy button
MediumButton = Button('mediumbutton',533,477,362,223,'MediumText',560,548,2) #Creates medium button
HardButton = Button('hardbutton',127,727,362,223,'HardText',214,806,2) #Creates hard button
VeteranButton = Button('veteranbutton',533,727,362,223,'VeteranText',537,806,2) #Creates veteran button
OneButton = Button('onebutton',127,477,362,223,'OneText',287,550,3) #Creates the level 1 button
TwoButton = Button('twobutton',533,477,362,223,'TwoText',693,550,3) #Creates the level 2 button
ThreeButton = Button('threebutton',127,727,362,223,'ThreeText',285,810,3) #Creates the level 3 button
FourButton = Button('fourbutton',533,727,362,223,'FourText',685,810,3) #Creates the level 4 button
PlayButton.createbutton() #Creates the play button through the button class and its method
QuitButton.createbutton() #Creates the play button through the button class and its method
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
mouse = pygame.mouse.get_pos() #Gets the x and y coordinates of the mouse cursor
pressed = pygame.mouse.get_pressed() #Checks if the mouse has been pressed
PlayButton.buttonaction() #Checks if the playbutton needs action
QuitButton.quitbutton() #Checks if the quitbutton needs action
EasyButton.buttonaction() #Checks if the easybutton needs action
MediumButton.buttonaction() #Checks if the mediumbutton needs action
HardButton.buttonaction() #Checks if the hardbutton needs action
VeteranButton.buttonaction() #Checks if the veteranbutton needs action
OneButton.buttonaction() #Checks if the onebutton needs action
TwoButton.buttonaction() #Checks if the twobutton needs action
ThreeButton.buttonaction() #Checks if the threebutton needs action
FourButton.buttonaction() #Checks if the fourbutton needs action
pressed = [0,0,0]
pygame.display.update()
clock.tick(5)
One of the principals of object oriented design is to keep all the aspects of what the object is modelling/implementing inside the object, but no more. What is the purpose of this "Button" - to be seen on-screen, to accept user input, to signal the state to the main program.
So in terms of this, your button class is mostly OK. However, it's including things inside the button definition that really are not the job of the button, for example:
def quitbutton(self):
#If the button is clicked (regarding its dimensions)
if self.buttonx+self.buttonwidth > mouse[0] > self.buttonx and self.buttony+self.buttonheight > mouse[1] > self.buttony and pressed[0] == 1:
pygame.quit() #Exits pygame
quit() #Quits program
A generic button class should not be responsible for quitting the program, it just needs to click and un-click. Similarly for the code that switches between the Play+Quit and the difficulty level button-sets - this is not the button's job.
I think a better button removes clutter to be simpler:
class Button:
def __init__(self, buttonname, buttonx, buttony, buttonwidth, buttonheight, textfile, textx, texty ):
self.buttonname = buttonname # Name of the button
self.buttonx = buttonx # X-axis position
self.buttony = buttony # Y-axis position
self.buttonwidth = buttonwidth # Width of the button
self.buttonheight= buttonheight # Height of the button
self.text_image = pygame.image.load( textfile+".png" ) # Button Label
self.textx = textx # X-axis positioning of the text
self.texty = texty # Y-axis positioning of the text
def drawButton( self, screen ):
""" Paint the button to the screen """
# Black rectangle the size of the button
pygame.draw.rect( screen, (0,0,0), [self.buttonx, self.buttony, self.buttonwidth, self.buttonheight])
# Overlay the button text onto the background
screen.blit( text_image, ( self.textx, self.texty ) )
def mouseIsOver( self, mouse_position ):
""" Returns true if the mouse is within this buttons area """
inside = self.buttonx+self.buttonwidth > mouse_position[0] > self.buttonx and self.buttony+self.buttonheight > mouse_position[1] > self.buttony
return inside
Then in your main program:
PlayButton = Button('playbutton',133,477,756,223,'rock1_64',387,545,1) #Creates play button
QuitButton = Button('quitbutton',133,731,756,223,'rock1_64',387,806,None) #Creates quit button
EasyButton = Button('easybutton',127,477,362,223,'rock1_64',214,548,2) #Creates easy button
MediumButton = Button('mediumbutton',533,477,362,223,'rock1_64',560,548,2)
...
all_buttons = [ PlayButton, QuitButton, EasyButton, MediumButton ]
# Main Loop
while True:
# Handle user-input
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
if event.type == pygame.MOUSEBUTTONUP:
# The mouse button was clicked, was it inside a button?
click_location = pygame.mouse.get_pos()
for b in all_buttons:
if ( b.mouseIsOver( click_location ) ):
print( "Button [%s] pressed" % ( b.buttonname ) )
# Re-paint screen
gameDisplay.fill( BACKGROUND_COLOUR )
for b in all_buttons:
b.drawButton( gameDisplay )
pygame.display.flip()
clock.tick_busy_loop( 60 ) # Limit FPS
pygame.quit()
quit()
Or failing that, the Button class could post and event to the PyGame queue:
(EDIT: There was a bug in this, it needed to create the event to post, FIXED).
BUTTON_CLICK_EVENT = pygame.USEREVENT + 1
...
class Button ( ... ):
def checkClick( self, mouse_pos ):
""" If the mouse-click is inside our rectangle, post a message to the queue """
if ( self.buttonx+self.buttonwidth > mouse_position[0] > self.buttonx and self.buttony+self.buttonheight > mouse_position[1] > self.buttony ):
pygame.event.post( pygame.event.Event( BUTTON_CLICK_EVENT, { "button_name" : self.buttonname } ) )
...
# Main loop
if event.type == BUTTON_CLICK_EVENT:
print("Clicked "+ event.button_name )
Doing this allows the separation of the button logic from the rest of the program, and prevents needing global variables. Obviously you have a need to switch between banks of buttons, but this is not a problem for the Button object, it should go somewhere else. Perhaps in a ButtonGroup or suchlike.
I searched in win32gui and PyAutoGUI some commands that make "long - click" on the left mouse button, and I didn't find anything.
I'm actually building a code that helps me to remote another pc's mouse
so i need a command that makes a long click on a mouse.
I put *** on my code so you can see the parts where I need help:
import win32api
import time
state_left = win32api.GetKeyState(0x01) # Left button down = 0 or 1. Button up = -127 or -128
while True:
a = win32api.GetKeyState(0x01)
if a != state_left: # Button state changed
state_left = a
print(a)
if a < 0:
# *** long click on left mouse button ***
print('Left Button Pressed')
else:
# *** stop click on left mouse button ***
print('Left Button Released')
time.sleep(0.001)
In theory, PyAutoGUI covers this with mouseDown & mouseUp functions.
>>> pyautogui.mouseDown(); pyautogui.mouseUp() # does the same thing as a left-button mouse click
>>> pyautogui.mouseDown() # press the left button down
>>> pyautogui.mouseUp(x=100, y=200) # move the mouse to 100, 200, then release the button up.
A solution might be:
pyautogui.dragTo(100, 200, button='left') # drag mouse to X of 100, Y of 200 while holding down left mouse button
pyautogui.dragTo(300, 400, 2, button='left') # drag mouse to X of 300, Y of 400 over 2 seconds while holding down left mouse button
pyautogui.drag(30, 0, 2, button='right') # drag the mouse left 30 pixels over 2 seconds while holding down the right mouse button
Yes, that title wasn't worded very properly at all.
Ok, here's what we've got - a Python program using the pyGame library, and we're making a game. We start in a menu environment main.py. When the user clicks on one of the menu buttons, an action is performed. The program checks for clicks on menu items using the following code:
if event.type == pygame.MOUSEBUTTONDOWN:
mousePos = pygame.mouse.get_pos()
for item in buttons: # For each button
X = item.getXPos() # Check if the mouse click was...
Y = item.getYPos() # ...inside the button
if X[0] < mousePos[0] < X[1] and Y[0] < mousePos[1] < Y [1]:
# If it was
item.action(screen) # Do something
When the user clicks on the "Play Game" button, it opens a sub-module, playGame.py. In this sub-module is another pyGame loop etc.
Part of the game is to hold the left mouse button to 'grow' circles out of the current position (It's a puzzle game, and it makes sense in context). Here is my code for doing this:
mouseIsDown == False
r = 10
circleCentre = (0,0)
[...other code...]
if mouseIsDown == True:
# This grown the circle's radius by 1 each frame, and redraws the circle
pygame.draw.circle(screen, setColour(currentColourID), circleCentre, r, 2)
r += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
runningLevel = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# User has pressed mouse button, wants to draw new circle
circleCentre = pygame.mouse.get_pos()
mouseIsDown = True
elif event.type == pygame.MOUSEBUTTONUP:
# Stop drawing the circle and store it in the circles list
mouseIsDown = False
newCircle = Circle(circleCentre, r, currentColourID)
circles.append(newCircle)
circleCount += 1
r = 10 # Reset radius
The problem I have is that the user's left mouse click from the main menu is persisting into the playGame.py module, and causing it to create and store a new circle, of radius 10 and at position (0,0). Both of these are the default values.
This only happens for the one frame after the menu.
Is there any way to prevent this, or is it a flaw in my code?
All help greatly appreciated, as always. If you need more code or explanation of these snippets, let me know.
If you'd like the full code, it's on GitHub.
You could use MOUSEBUTTONUP instead of MOUSBUTTONDOWN in the menu.
Does adding pygame.event.clear() to the top of Play fix it?