Variable adds itself for unknown reason - python

(EDIT #1)
I am new to coding and tried to create an infinite grid and a way to drag/move the grid using the mouse when any mouse button is pressed.
What I am trying to do is take the coordinates of the mouse right before any mouse button is pressed.
Then calculate the difference in coordinates while mouse is being moved in real time from that starting position (without releasing the button).
Then I want to save that difference and use it to move the grid (after mouse button is released).
After that, when I release any mouse button and the grid was successfully moved, I want to then be able to drag it again without resetting the already existing coordinates of the grid.
The problem with all of this is: when any mouse button is held down and is not being released, if moved from its starting point and then stopped at another location than the starting, the variable "CPD" representing the difference between starting and current mouse position adds itself, yet I do not see why that is supposed to be happening. It is an "=" sign and not "+=" nor is itself specified when measuring the difference and the "if" is not triggered at all, only the "else" is!
SP - Starting position of the mouse (right before left mouse button is pressed). CP - Current position of the mouse. PPD - The previous difference in starting and current mouse position. CPD - Current difference in starting and current mouse position.
This is the continuation of the previous picture (couldn't fit everything in one)
import time
import mouse
CPD = [0, 0] # Current difference in the starting and curruent mouse position
PPD = [0, 0] # Previous difference in the starting and curruent mouse position
CP = [0, 0] # Current position of the mouse
SP = [0, 0] # Position of the mouse right before any mouse button is pressed
# the loop (obviously) so it can check again and again so that the difference would be seen in real time.
while True:
# simply a way to slow down the code to see the difference step by step
time.sleep(1)
# Saves the position of the mouse [x, y] and the previous difference in starting and current mouse position until any mouse button is pressed
if not mouse.is_pressed():
PPD = CPD
SP = list(mouse.get_position())
# Then, if any mouse button is pressed: it finds current mouse's position
# Then it calculates the difference in starting and current mouse positions for x first and then y after which it stores the result
else:
CP = list(mouse.get_position())
for position in range(2):
CPD[position] = PPD[position] + CP[position] - SP[position]
# all the variable results after math
print(f"Mouse is pressed: {mouse.is_pressed()}\nSP: {SP}\nCP: {CP}\nPPD: {PPD}\nCPD: {CPD}\n")
I have tried to figure it out for a very long time and neither could my friend who is decent at coding (I believe). Any ideas?

The confusion here for you is - I think - coming from the interpretation of mouse.is_pressed(). This function returns you the current state, not a change of state. So throughout the whole time you have the button pressed, it returns True. It is not that, when you first time access this method, it is somehow reset to False again. Only when you release the mouse button again.
That also explains, why it is being added again and again: You have a loop and check for it every 0.1 seconds.

is_pressed() gives True all time when you keep pressed button.
You would have to remeber previous value and execute code only when previous state is False and current state is True
Somethink like this
import time
import mouse
Current_Position_Difference = [0, 0]
Previous_Position_Difference = [0, 0]
Start_Position = [0, 0]
previous_state = False
while True:
time.sleep(0.1)
current_state = mouse.is_pressed()
if current_state is False:
Previous_Position_Difference = Current_Position_Difference
Start_Position = list(mouse.get_position())
else:
if previous_state is False:
Current_Position = list(mouse.get_position())
for position in range(2):
Current_Position_Difference[position] = Previous_Position_Difference[position] + Current_Position[position] - Start_Position[position]
previous_state = current_state
print(Current_Position_Difference)
But mouse has also mouse.on_click(callback) to run function callback() only once when you press button. And on_click doesn't need to run in while-loop.
I don't know what you try to do in your code so I don't know if this code works the same
import time
import mouse
# --- function ---
def my_function():
print('clicked', mouse.get_position())
Current_Position = list(mouse.get_position())
for position in range(2):
Current_Position_Difference[position] = Previous_Position_Difference[position] + Current_Position[position] - Start_Position[position]
# --- main ---
Current_Position_Difference = [0, 0]
Previous_Position_Difference = [0, 0]
Start_Position = [0, 0]
mouse.on_click(my_function)
while True:
time.sleep(0.01)
Previous_Position_Difference = Current_Position_Difference
Start_Position = mouse.get_position()
print(Current_Position_Difference)
Other modules may have also on_move(callback) to run function only when mouse change position.

Related

Python - get raw mouse input

I want to use Python to read raw data from the mouse (e.g. left signal, right signal) independent of the mouse pointer. I don't want to read the position of the cursor, I want to read the raw data, akin to how a game would. How can I do that? I can't find any libraries that support it.
I'm using Windows.
Edit: To clarify, when I said "left signal and right signal", I meant mouse movement, not mouse clicks,
Edit 2: I believe the terminology is that I want the "mouse delta." This is how people did it in autohotkey - https://www.autohotkey.com/boards/viewtopic.php?t=10159 - but I want it in Python.
Edit 3: I should mention that this is in a game that constantly resets pointer position, so I can't use the difference in pointer position. That's why I want a lower level API.
Get the mouse position and compare two events. If the x-axis value increases, the mouse moved right, if the x-axis value decreases, the mouse moved left:
from pynput.mouse import Listener
last_position = None
def on_move(x, y):
global last_position
if last_position:
if x > last_position:
print('mouse moved right')
elif x < last_position:
print('mouse moved left')
last_position = x
with Listener(on_move=on_move) as listener:
listener.join()
You can always compare the position constantly that would have easily given you a delta. Any lower level API you will have to code a mouse driver yourself, which is what game developers do to prevent people from scripting, which isn't what python made for.
import pyautogui
import time
while True:
prev_x, prev_y = pyautogui.position()
time.sleep(0.3)
curr_x, curr_y = pyautogui.position()
if (curr_x - prev_x) > 0:
print("move right")
else:
print("move left")

I want to move the turtle in a certain path and at the same time, I want to save all the pixels it moves through in a list of variables

I need to save each and every pixels the turtle moves through as it moves from say(-305,305) to (205,305).
I want to save each and every of those coordinates on the path in a variable. Is there anyway to do it?
I.
You need some kind of mechanism for intervention to the drawing process,
similar to the update function in the Tkinter library and the callback functions of the OpenGL library.
There is an ontimer function in the Turtle library, which can perform some action
(in your case - insertion into a list) after a given time period.
This method is shown below. It works but have some limitations:
1. it doesn't work if drawing speed is fastest ( turtle.speed('fastest') ),
2. it doesn't want to insert a very first pair of coordinates in a list - you have to do this insertion by yourself,
3. Some parts of a drawing may have gaps. When replaying from a list, which stores coordinates only, such situation is not processed (you will get a drawing without gaps).
import turtle as tr
from turtle import *
time = 3 # 3 milliseconds period
status = False
coord=[] # List of coordinates
sx, sy = -305, 305 # Start point
ex, ey = 205, 305 # End point
def func(): # Timer callback function
if status:
coord.append([tr.xcor(),tr.ycor()]) # list of lists
# coord.append(pos()) # list of tuples
ontimer(func, t = time)
def redraw(): # Replay function
tr.up()
tr.goto(coord[0][0], coord[0][1])
tr.down()
for i in range(1, len(coord)):
tr.goto(coord[i][0], coord[i][1])
def restart2(): # Keyboard callback function
tr.reset()
redraw()
tr.screensize(768, 512) # Preliminary actions
tr.setup(width = 1.0, height = 1.0)
tr.onkeypress(restart2)
tr.listen()
tr.up()
tr.goto(sx,sy)
coord.append([sx, sy]) # Manual recording of the first point - list of lists case
#coord.append(tr.pos()) # list of tuples case
status = True
tr.ontimer(func, t = time) # Start timer
tr.down()
tr.goto(ex, ey) # Main drawing process
status = False # "Stop" timer (timer pause for this example)
tr.up()
tr.home()
coord.append([tr.xcor(), tr.ycor()]) # Manual recording of the first point after gap
status = True
tr.ontimer(func, t = time) # Continue timer
tr.down()
while True: # Examlpe from the Turtle library docs
tr.forward(200)
tr.left(170)
if abs(tr.pos()) < 1:
break
tr.home()
tr.circle(50)
tr.circle(120, 180)
status = False # "Stop" timer
print(coord) # print to console
tr.done()
Press any key for replay path from the list.
II.
A lot of drawings have analytical solutions. It is much simpler then store a lot of coordinates.
It is probably simpler (but not faster?) to store the coordinates of the beginning and the end of drawing parts and to calculate desired intermediate points analytically.

How to register coordinates and draw a line?

Using pyqt I set up a ViewBox widget, and inside that widget I need to register two clicks of my mouse to draw a line using pyqtgraph roi that connects the clicks.
This is my base code with comments what I would like it to do:
def onClick(ev):
#First mouse click - ONLY register coordinates
#Second mouse click - register coordinates of second click
#Draw line connecting the two clicks
w.scene().sigMouseClicked.connect(onClick)
This code works to return a mouseclick and draw a line, BUT I don't know how to make it wait for the second mouseclick:
def onClick(ev):
x = ev.pos().x()
y = ev.pos().y()
print(x,y)
line = pg.LineSegmentROI([[711,265], [295, 170]], pen=(4,9))
vb.addItem(line)
w.scene().sigMouseClicked.connect(onClick)
This is mostly untested code, but should get you where you want to go. Basically, you have a global array, which contains either one or two sets of coordinates. If the array is empty when the handler is called, that mean you're dealing with the first click, and you store those coordinates. If the array already contain one set of coordinates, you're dealing with the second click and you can draw your line, but don't forget to empty the array so it can work again if you click a third time
clicks = []
def onClick(ev):
global clicks
x = ev.pos().x()
y = ev.pos().y()
if len(clicks)==0: # First mouse click - ONLY register coordinates
print("First click!")
clicks.append((x,y))
elif len(clicks)==1: # Second mouse click - register coordinates of second click
print("Second click...")
clicks.append((x,y))
# Draw line connecting the two clicks
print("...drawing line")
line = pg.LineSegmentROI(clicks, pen=(4,9))
vb.addItem(line)
# reset clicks array
clicks[:] = [] # this resets the *content* of clicks without changing the object itself
else: # something went wrong, just reset clicks
clicks[:] = []

How do I get an image to move until it gets to a specific point in the window?

Right now I have some code in Python using Zelle graphics that has a robot image and some text scrolling upward. When the user clicks on the window, the program ends.
What I'm trying to do is have pieces of the robot image come in from opposite sides of the window (The head moving down from the top, the eyes moving up from the bottom, and the ears moving in from the left and right). They would stop moving once they come together to form the completed image.
After that, I want the text to come in from the left hand side and stop once it gets to the center of the screen, underneath the image. I don't want the animation to start until the user clicks on the window.
This is what my code looks like so far:
from graphics import *
from random import randint
from time import sleep
screen=GraphWin("Logo",500,700);
screen.setBackground("#b3e2bf");
#---------logo-----------
robotHead=Image(Point(250,250),"robotHead.png");
robotHead.draw(screen);
robotEyes=Image(Point(250,310),"robotEyes.png");
robotEyes.draw(screen);
robotLeftEar=Image(Point(150,290),"robotLeftEar.png");
robotLeftEar.draw(screen);
robotRightEar=Image(Point(350,290),"robotRightEar.png");
robotRightEar.draw(screen);
#--------credits-----------
programmer=Point(250,515);
lineOne=Text(programmer,"Programmer Name");
lineOne.draw(screen);
className=Point(250,535);
lineTwo=Text(className,"CSC 211");
lineTwo.draw(screen);
date=Point(250,555);
lineThree=Text(date,"November 30th, 2017");
lineThree.draw(screen);
copyrightName=Point(250,575);
lineFour=Text(copyrightName,"Copyright Line");
lineFour.draw(screen);
while screen.checkMouse()==None:
robotHead.move(0,-1);
robotEyes.move(0,-1);
robotLeftEar.move(0,-1);
robotRightEar.move(0,-1);
lineOne.move(0,-1);
lineTwo.move(0,-1);
lineThree.move(0,-1);
lineFour.move(0,-1);
sleep(0.1);
screen.close();
You can use robotHead.anchor.getY() and robotHead.anchor.getX() to check current position and move it only if it is not on expected position.
You can also use variables with True/False to control which element has to move (or even which element to show on screen). At start you should have moveHead = Trueand moveLineOne = False. When head is on expected position then you can change moveHead = False and moveLineOne = True.
BTW: graphics has function update(frames_per_second) to control speed of animation and you don't need sleep(). Besides update() executes some functions which graphics may need for correct work. (graphics documentation: Controlling Display Updates (Advanced))
Speed 25-30 FPS is enough for human eye to see smooth animation (and it may uses less CPU power than 60 FPS).
Simple example
from graphics import *
from random import randint
from time import sleep
screen = GraphWin("Logo", 500, 700)
# --- objects ---
robot_head = Image(Point(250, 250), "robotHead.png")
robot_head.draw(screen)
programmer = Point(250, 515)
line_one = Text(programmer, "Programmer Name")
#line_one.draw(screen) # don't show at start
# --- control objects ---
move_robot_head = True # move head at start
move_line_one = False # don't move text at start
# --- mainloop ---
while not screen.checkMouse(): # while screen.checkMouse() is None:
if move_robot_head: # if move_robot_head == True:
# check if head is on destination position
if robot_head.anchor.getY() <= 100:
# stop head
move_robot_head = False
# show text
line_one.draw(screen)
# move text
move_line_one = True
else:
# move head
robot_head.move(0, -10)
if move_line_one: # if move_line_one == True:
# check if head is on destination position
if line_one.anchor.getY() <= 150:
# stop text
move_programmer = False
else:
# move text
line_one.move(0, -10)
# control speed of animation
update(30) # 30 FPS (frames per second)
# --- end ---
screen.close()

Single mouse click within While loop (PsychoPy)

I am using PsychoPy and I would like to print the position of my mouse when it has been clicked.
The actual printing of the position needs to be placed inside a while loop. Using the code below, when I click I get more than one output lines, which print the same positions. I would like to have only one output printing for each click.
This is the code I am using:
#!/usr/bin/env python2
from psychopy import visual, core, event
from pyglet.gl import *
width = 600
height = 600
myWin = visual.Window([width,height], color='white',units='pix',monitor='testMonitor')
#This will set the windows units (pixels) to GL units
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, width, 0, height, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_BLEND)
glBlendFunc(GL_ZERO, GL_SRC_COLOR)
myMouse = event.Mouse() # will use myWin by default
while True:
#Triangle left
glColor3f(1.0, 0.0, 0.0)
glBegin(GL_TRIANGLES)
glVertex3f(150, 550, 1)
glVertex3f(50, 350, 1)
glVertex3f(250, 350, -1)
glEnd()
if myMouse.getPressed()[0]:
myMouse.clickReset()
print myMouse.getPos()
myWin.flip()
core.quit()
Is there something wrong I am doing? Should the 'frame rate' of the while loop be changed?
I've not used the module, but it seems like mouse events are thrown for mouse raises as well.
You'll need to
Store the mouse state for next time
Each iteration, test whether the mouse state for button 0 has gone up → down
The mouse state is returned by myMouse.getPressed.
So something like:
oldMouseIsDown = False
while True:
...
mouseIsDown = myMouse.getPressed()[0]
myMouse.clickReset()
if mouseIsDown and not oldMouseIsDown:
print myMouse.getPos()
oldMouseIsDown = mouseIsDown
Veedrac's answer is correct. Your code is using the typical PsychoPy pattern of checking for events once every time the window is redrawn. This will typically be happening at least at 60 Hz. So unless you manage to press the mouse button for less than 16.7 ms (or less for a faster screen), you will detect it multiple times as being pressed, as each time you check on successive window redraws, the mouse button remains down. Even though it was pushed only once, the duration of the push is not instantaneous.
As Veedrac suggests, you therefore need to maintain the previous state of the mouse button in a variable so that you can choose to only print the position once. Mouseup events are not relevant here: you are purely testing for whether the button is currently pressed.
I had a very similar problem and fixed it in a slightly different way from the accepted answer. The advantage of this one is that you can set how long you want to 'desensitize' the mouse after a click (i.e. to prevent longer clicks from triggering your if loop multiple times). Depending on your mouse or the user's click release speed you can change minFramesAfterClick:
minFramesAfterClick = 10 # to prevent re-entering the if loop too early
myMouse.clickReset()
timeAfterClick = 0
while True:
timeAfterClick += 1
if myMouse.getPressed()[0] and timeAfterClick >= minFramesAfterClick:
print myMouse.getPos()
myMouse.clickReset()
timeAfterClick = 0
myWin.flip()
By the way, the reason why the OP couldn't get Veedrac's answer work is because line oldMouseIsDown = mouseIsDown should be placed it inside the if loop rather than after it (not enough reputation to comment there).

Categories

Resources