PyUserInput - stopping PyMouseEvent - python

I am trying to build a program whose first part is saving user clicks for calibration purposes.
I am using PyUserInput for this (on Python 3.4.3) and following their tutorial on GitHub. Currently, this is my code:
from pymouse import PyMouseEvent
positions = []
class Click(PyMouseEvent):
def __init__(self):
PyMouseEvent.__init__(self)
def click(self, x, y, button, press):
if button == 1:
if press:
print('Click! X=%d - Y=%d' % (x, y))
positions.append((x, y))
print(positions)
if len(positions) >= 4:
self.stop()
C = Click()
C.run()
print('Calibrated')
The problem I'm running into is that, even after the PyMouseEvent stops (when position reaches 4 values), I cannot run anything after it (i.e. 'Calibrated' does not print).
How can I continue to run scripts after calling stop() on PyMouseEvent?
I appreciate any help.

This is more of a workaround than a "legal" solution. The idea is to replace stop() method calls with raising exception and wrapping run() method call inside try: except: statements. I recommend making your own exception by subclassing Exception for better understanding of the code.
Here:
from pymouse import PyMouseEvent
positions = []
class ListenInterrupt(Exception):
pass
class Click(PyMouseEvent):
def __init__(self):
PyMouseEvent.__init__(self)
return
def click(self, x, y, button, press):
if button == 1:
if press:
print('Click! X=%d - Y=%d' % (x, y))
positions.append((x, y))
print(positions)
if len(positions) >= 4:
raise ListenInterrupt("Calibrated.")
return
C = Click()
try:
C.run()
except ListenInterrupt as e:
print(e.args[0])
This should stop event listener. If you wish to recalibrate using this approach, simply reruning same instance of listener won't work. The solution is deleting current instance of class Click and instantiating new one each time.
del C
C = Click()

Related

Can you use curses syntax with normal python functions?

I want to create a software program that has a main menu with options that are navigable with arrow keys (I have the code for this). When the user clicks on the option they want, it loads in the associated function. Can I use normal python syntax as the function and have the curses syntax call the function? How can I do this?
import curses
menu = ['Set Wallet Address', 'Start BTC Miner', 'Currency', 'Exit']
def clr():
print("\n"*60)
#center everything
def print_menu(stdscr, selected_row_idx):
stdscr.clear()
h, w = stdscr.getmaxyx()
for idx, row in enumerate(menu):
x = w//2 - len(row)//2
y = h//2 - len(menu)//2 + idx
if idx == selected_row_idx:
stdscr.attron(curses.color_pair(1))
stdscr.addstr(y, x, row)
stdscr.attroff(curses.color_pair(1))
else:
stdscr.addstr(y, x, row)
stdscr.refresh()
#print everything in center
def print_center(stdscr, text):
stdscr.clear()
h, w = stdscr.getmaxyx()
x = w//2 - len(text)//2
y = h//2
stdscr.addstr(y, x, text)
stdscr.refresh()
def test(stdscr):
clr()
print_center(stdscr, 'Hello')
def main(stdscr):
# turn off cursor blinking
curses.curs_set(0)
# color scheme for selected row
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
# specify the current selected row
current_row = 0
# print the menu
print_menu(stdscr, current_row)
while 1:
key = stdscr.getch()
if key == curses.KEY_UP and current_row > 0:
current_row -= 1
elif key == curses.KEY_DOWN and current_row < len(menu)-1:
current_row += 1
elif key == curses.KEY_ENTER or key in [10, 13]:
test(stdscr)
stdscr.getch()
# if user selected last row, exit the program
if current_row == len(menu)-1:
break
print_menu(stdscr, current_row)
curses.wrapper(main)
Lots of ways to do this but the statements "can you use curses syntax" and "have the curses syntax call the function" doesn't make sense? There's only Python syntax and some no-so-magic from the curses module's wrapper function that you pass main to which the wrapped calls by passing it a scr that curses handles/wraps IOT cleanly exit. curses and _curses are just modules based on C's ncurses.
I think you're on the right track though so your goal is achievable and while I didn't run your code it looks close as well. Yes you can write a basic python function. You could use the same default scr or you could also spawn a new initscr or derived scr (see the Python curses docs). I would start small and bind a single key to each option to ensure your callbacks work first. So if you bind 'h' to a help screen, just read getch and compare ord/char 'h', and if matches call a help() function (or create a callback of sorts by passing the function help to some other function to execute/wrap) so as to redraw the scr with help info. Then later work in cursors as you'll need to remember the cursor state and integrate with a list of callback functions.

How do I assign values to a variable with a schedule function in pyglet?

With the following code
x=1.0
def update(dt):
space.step(dt)
def xprinter(self, x):
print (x)
return x+1
if __name__ == "__main__":
x=pyglet.clock.schedule(xprinter,x)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
My return is simply 1.0 over and over. I would like for the value to be updated with each call. What am I missing?
The design here is based on that your function rely on returning a result.
Which causes a problem because Pyglet's internal functions are in charge of executing that function at a interval, meaning you're not the one executing the call - and there for you're not the one getting that return value, Pyglet is.
And since there's no meaningful way for Pyglet to relay that returned value (there are ways, but they involve hooking in and overriding certain internal functions), you will never see that return value.
The quick and easy workaround would be to do:
x=1.0
def update(dt):
space.step(dt)
def xprinter(self):
global x
print(x)
x += 1
if __name__ == "__main__":
pyglet.clock.schedule(xprinter)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
This way, the schedule call will update the global variable x rather than returning the result of the math equation.
A more neat approach would be to define a class with the x attribute and pass a class instance to the pyglet.clock.schedule():
class player():
def __init__(self):
self.x = 0
def update(dt):
space.step(dt)
def xprinter(self, p):
print(p)
p.x += 1
if __name__ == "__main__":
p = player()
x = pyglet.clock.schedule(xprinter, p)
pyglet.clock.schedule_interval(update, 1.0/60)
pyglet.app.run()
And if I'm not completely out of the ball park, this would remember the value across clock ticks, because of the instance.
This is also usually what you'll be using the schedule for, doing player / game / animation updates.

Raspberry Pi - Python - joystick

I am using Raspberry Pi.
while True:
if joystick.get_button(0) == 1:
print ("stop")
else
print ("start")
The purpose of this code is :
I want to interrupt some action while I press a button.
while running the code, it ignores me when I press the button and keep giving me "start". However, if I change the code to :
if joystick.get_button(0) == 0:
the program gives me "stop" at once. (0 is the default value of get_button(0), 1 means I press the button)
The cycle itself seems ok, so I would think that the problem is how your get_button() method acts. Be sure that it is returning the right value and that infinite loop and status checking are not running in the same thread.
Anyway, I would suggest you to use the Observer Pattern.
Basically, it allows you to create a reaction over your joystick button without using infinite loops.
The following code should fit your needs. Joystick class call methods from Player class every time the button is pressed, so every time Joystick change its state.
//OBSERVABLE OBJECT
class Joystick(object):
def __init__(self):
self._button = 0
self._observers = []
def get_button(self):
return self._button
def set_button(self, value):
for callback in self._observers:
callback(self._button)
def bind_to(self, callback):
self._observers.append(callback)
//OBSERVER OBJECT
class Player(object):
def __init__(self, controller):
self._state = 0; //1 - stop, 0 - play
self.controller.bind_to(self.change_state)
def change_state(self, new_state):
self_state = new_state
if(new_state == 0)
print 'play'
else
print 'stop'
This solution will print 'play' and 'stop' once, on every state change.
Then in your code you will create an observable instance:
joystick = new Joystick()
and pass it to an observer:
player = new Player(joystick)
in this way, when you launch your setter function:
joystick.set_button(0)
joystick will automatically change the status in player instance.

Urwid horizontal menu - return to previous state or restart loop

I'm building an app based on the Horizontal Menu example from Urwid.
I have an item that I want to show some information. I have an "OK" button underneath, and I want it to either pop the menu back to the previous state, or maybe restart the entire screen/loop.
In the example, they use ExitMainLoop(), but I don't want to exit - I just want to restart it.
So, I've changed the callback to a different function - but all my attempts either do nothing or crash my program.
Here's the relevant bits:
Starting the menu:
if __name__ == "__main__":
top = HorizontalBoxes()
top.open_box(menu_top([]).menu)
urwid.MainLoop(urwid.Filler(top, 'middle', 40), palette).run()
Relevant menu class/functions. My problem is - what goes in the does_nothing function?
class Choice(urwid.WidgetWrap):
def __init__(self, caption, pid):
super(Choice, self).__init__(
MenuButton(caption, partial(self.item_chosen,pid)))
self.caption = caption
def item_chosen(self, pid, button):
if self.caption == (u"System status"):
showSystemStatus()
def showSystemStatus():
response = urwid.Text( "... some text ")
done = MenuButton(u'OK', does_nothing)
response_box = urwid.Filler(urwid.Pile([response,done]))
top.open_box(urwid.AttrMap(response_box, 'options'))
def does_nothing(key):
????????????????????
return
I found a solution!
I had to add a new method to the HorizontalBoxes class. Specifically, the close_box method:
class HorizontalBoxes(urwid.Columns):
def __init__(self):
super(HorizontalBoxes, self).__init__([], dividechars=1)
def open_box(self, box):
if self.contents:
del self.contents[self.focus_position + 1:]
self.contents.append((urwid.AttrMap(box, 'options', focus_map),
self.options('given', 40)))
self.focus_position = len(self.contents) - 1
def close_box(self):
if self.contents:
del self.contents[self.focus_position :]
self.focus_position = len(self.contents) - 1
And then, it was a simple matter of calling the close_box method from my does_nothing function from before:
def does_nothing(key):
top.close_box()
return

Extract value from a list in another function in Python

I am programming a robot and I want to use an Xbox Controller using pygame. So far this is what I got (original code credits to Daniel J. Gonzalez):
"""
Gamepad Module
Daniel J. Gonzalez
dgonz#mit.edu
Based off code from: http://robots.dacloughb.com/project-1/logitech-game-pad/
"""
import pygame
"""
Returns a vector of the following form:
[LThumbstickX, LThumbstickY, Unknown Coupled Axis???,
RThumbstickX, RThumbstickY,
Button 1/X, Button 2/A, Button 3/B, Button 4/Y,
Left Bumper, Right Bumper, Left Trigger, Right Triller,
Select, Start, Left Thumb Press, Right Thumb Press]
Note:
No D-Pad.
Triggers are switches, not variable.
Your controller may be different
"""
def get():
out = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
it = 0 #iterator
pygame.event.pump()
#Read input from the two joysticks
for i in range(0, j.get_numaxes()):
out[it] = j.get_axis(i)
it+=1
#Read input from buttons
for i in range(0, j.get_numbuttons()):
out[it] = j.get_button(i)
it+=1
first = out[1]
second = out[2]
third = out[3]
fourth = out[4]
return first, second, third, fourth
def test():
while True:
first, second, third, fourth = get()
pygame.init()
j = pygame.joystick.Joystick(0)
j.init()
print 'Initialized Joystick : %s' % j.get_name()
test()
Do you see the list called "out"? Each element in it is a button on the Xbox Controller. I want to extract those elements and put them on variables, one variable to each element/button so I can control my robot.
How could I do it?
I've tried to use global variables but then everything turned down to a mess.
Please note that I am a beginner in Python.
If you want to have out in your program then just return it from your function get:
def get():
# rest of the code ...
return out
Also change your function test:
def test():
while True:
out = get()
LThumbstickX = out[0]
LThumbstickY = out[1]
# and so on
Then run your program as before. What the function test does is constantly (while True) read the keypad. You could for example do:
def test():
while True:
out = get()
LThumbstickX = out[0]
if LThumbstickX != 0:
print 'Left button has been pressed'
# and so on
You can just return the list and use python's unpacking feature:
def get():
out = [1,2,3,4]
return out
first, second, third, fourth = get()

Categories

Resources