I just started working with the rethink robotics baxter.
In their example for responding to button controls they use event handlers (I think).
Example (from gripper_cuff_control.py):
self._open_io.state_changed.connect(self._open_action)
I want to be able to push a button and move the wrist a set amount, I can currently do that, but it happens twice (once for state_changed -> pushed and once for state_changed -> released)
What is the most elegant way to make it so that the action only happens once on when a button is pushed and released?
I couldn't find documentation on the API, but from this example it looks like the first parameter to the function will tell you whether the button was pressed or released.
def _open_action(self, value):
if value: #button was pressed
#do stuff here in response to button press
else: #button was released
#do stuff here in response to button release
Related
I want to make a program or when I click on a key the mouse clicks automatically (as long as I click on the key) if I do not click on the key it stops.
I don't want the clicks to happen only when I touch the key once, but as long as the key is held down (It can also be the left button of the mouse pressed that trigger clicks like razer synapse mouses)
Any Idea ?
EDIT 1 :
This one works but not when a key is held down (even when the click is held down it doesn't work anyway) it only detects a single click on the mouse and then it clicks by itself instead of clicking ONLY when the key is held down...
import pyautogui, time
from pynput import mouse
from pynput.mouse import Button,Controller
from tkinter import *
from tkinter import ttk
root = Tk()
root.geometry('500x400')
combo = ttk.Combobox(root,values=['ctrl','shift','alt'],width=5)
combo.set('Key...')
combo.pack()
def on_click(x, y, button, pressed):
if button == mouse.Button.left:
while pressed:
pyautogui.click()
pyautogui.PAUSE = 0.1
else:
return False
with mouse.Listener(
on_click=on_click
) as Listener:
Listener.join()
root.mainloop()
You can use the mouse module (pip install mouse) to setup mouse hooks (hotkeys) that will let you trigger the clicking globally. However, in order to manage the beginning and end of this clicking, you will need to use a new thread (here is a short intro to threading if you want to learn more about it). You will want to start a thread when you press down your hotkey. This thread will continuesly click until you trigger an event that stops it. You will trigger this event by releasing your hotkey. Thus, the thread (and with it the clicking) will begin when you press the hotkey down and end when you let it back up.
Here is a piece of code that does exactly that using the middle (scroll) mouse button as the hotkey:
import mouse # pip install mouse
import threading
import pyautogui
pyautogui.PAUSE = 0.1 # set the automatic delay between clicks, default is 0.1
def repeat_function(kill_event):
# as long as we don't receive singal to end, keep clicking
while not kill_event.is_set():
pyautogui.click()
while True:
# create the event that will kill our thread, don't trigget it yet
kill_event = threading.Event()
# create the thread that will execute our clicking function, don't start it yet
new_thread = threading.Thread(target=lambda: repeat_function(kill_event))
# set a hook that will start the thread when we press middle mouse button
mouse.on_button(new_thread.start, (), mouse.MIDDLE, mouse.DOWN)
# set a hook that will kill the thread when we release middle button
mouse.on_button(kill_event.set, (), mouse.MIDDLE, mouse.UP)
# wait for user to use the hotkey
mouse.wait(mouse.MIDDLE, mouse.UP)
# remove hooks that used the killed thread and start again with a new one
mouse.unhook_all()
If you want to use the right mouse button instead, replace mouse.MIDDLE with mouse.RIGHT. I would not recommend using the left mouse button as the hotkey, as pyautogui will simulate clicking this button and likely break the program. If you want to use a key on the keyboard as the hotkey, check out the keyboard module. The concept there is the exact same.
Note that as this code is implemented, it will not be able to do anything else while waiting for the hotkey and processing it. You will need to use it as a separate python program if you want to use it as-is. You could also implement this code to run in a separate thread during another program, but it would definitely be easier to just launch it as a stand-alone script.
I have a wxpython dialog (wrapped in a function call which returns user selection) that Im using to prompt user for "ok", "cancel" type questions.
I have another thread that is running that allows the user to click a button and perform an emergency stop (also wxpython). when the emergency stop button is clicked, it performs some stuff and then displays its own user dialog.
Now, assume that a popup message has prompted the user with a yes/no question and at the very same time, the user sees something on fire and decides to click the emergency stop.
I need to be able to destroy the current dialog question and eventually display the dialog thats part of the estop thread.
Ive created code that starts the dialog in one thread and another that issues a pub.sendMessage(...) to kill the dialog thread if its displayed on the screen at the time of pressing the estop button.
This works just fine.
Problem is, i cant get the result from the user dialog (yes,no,cancel etc) because the thread never joins back to return what the user picked.
If i add a .join() to my code, i get the user response, but the dialog isnt destroyed if a pub.sendMessage(...) is sent.
heres pseudocode:
1)start up thread to monitor user emergency stop button push
2)start up test which may contain popup window (custom wxdialog) prompting user for answer
3)return user selection from dialog if selected
OR if user has clicked estop button: destroy current dialog and display new dialog related to estop
simple enough, but with the implementation of wrapper functions (this is code for others to call and needs to provide simple function calls), its obviously a little weird. but reimplementing it might not fly right now
heres some code (both are part of larger class so thats why the self references are there)
#the receiver of the pub message first:
def DestroyUI(self):
print 'into destroy'
#self.Hide()
#self.Close()
self.Destroy()
#these 2 fuctions are part of a different class
def closeDialogs(self):
print 'into closeDialogs'
def destroyUI():
if self.okToKill:
print 'closing wx dialogs'
pub.sendMessage("destroyUI")
ts = threading.Thread(target = destroyUI)
ts.start()
ts.join()
def MB(self,blah,blah):
def runMB(*args):
self.okToKill= True
self.response = self.PromptUser(*args)
self.okToKill= False
tr = threading.Thread(target = runMB,args=(blah,blah))
tr.start()
#if i add the join back in, i always return the user values
#but the dialog is never destroyed (if needed) before user
#clicks.
#without the join, the destroy pub send works great, but the
#user values are never returned
#tr.join()
return self.response
I have tried using queues, multiprocess pool, but the problem with those is the q.get() and async_result().get() both block until user clicks and therefore wont allow the destroy to work as needed.
What id love to figure out is how to get the user values IF the user clicked buttons, but also be able to destroy the current dialog and display the new emergency stop dialog instead (with custom buttons).
I wish wxpython just had a closeAll() :)
Also, i have tried closing the windows based on title name, and while that works, it hoses up my wx instance for the next dialog.
Any ideas?
thanks
since i dont really understand what you are asking for, I will instead address "I wish wxpython just had a closeAll() :)"
def wx_closeAll():
for win in wx.GetTopLevelWindows():
win.Destroy()
def closeAllButPrimary():
for win in wx.GetTopLevelWindows():
if win != wx.GetTopLevelWindow():
win.Destroy()
note this will close all frames and dialogs whose parent is None ... if you set a parent for the frame or dialog that dialog will be closed when its parent window is closed
Doing GUI from threads is not a good idea, and nearly always gives unexpected results.
In order to show the message box from a thread, you need to make the thread ask the main thread to show the message box.
You do this using the function wx.CallAfter
I'm talking about <<NotebookTabChanged>> event that ttk.Notebook can be bound to. Say I have:
def tabChanged(self, event):
print "tab changed"
And say I want to manually trigger this method. What I actually mean by this is, say I have a basic, tabbed GUI and there's a start button which makes plots when you click it. There are plots on each tab and when you change tabs, <<NotebookTabChanged>> is triggered, which is an automatically created event by ttk.Notebook. I already have a self.tabChanged method for this case. What I wanna do is, I wanna make my start button trigger this event so I don't have to create a new method just for the button which will do the exact same thing as self.tabChanged. So I need a way of triggering the event through a button click, but remember, that event is ttk.Notebook's own event and apparently it was designed to be used with tabs, not buttons. Is there a way to trigger <<NotebookTabChanged>> manually with a button click?
You can generate virtual events (eg: events that begin and end with << and >>) with event_generate:
self.the_notebook.event_generate("<<NotebookTabChanged>>")
My question today is, that I'd like to know, if there's a way to detect a mouse button NOT pressed using canvas.bind().
I want to know that, because I want to save data while a button is pressed, and to stop saving data when the button is not pressed anymore.
I want to do this with the left mouse button / ''
If you don't know what I wan't to do; feel free to ask in the comments :/
Detect mouse press and release events. When one of those events occur, start or stop saving as appropriate.
canvas.bind("<Button-1>", start_saving)
canvas.bind("<ButtonRelease-1>", stop_saving)
I'm in the process of creating a filling program with Python 3.3/Tkinter and have run into an issue that's really stumping me. Basically, I want to prevent button presses from registering while certain processes are taking place. I tried changing the button's state to state='disabled' but this only delays the click from registering until after the function is finished running. In other words, despite the button being "disabled", if it's clicked, the button press will register as soon as it's re-enabled. Please see the example code below.
def Button_Action:
Button.config(state='disabled')
#Activate some hardware that takes a few seconds.
Button.config(state='normal')
So, the question is: How can one selectively ignore button presses in Tkinter/Python 3?
I'm really new to Python and have tried searching for relevant questions to no avail, so please forgive me if this is a stupid question, or has been asked before. Also, I have tested this with both Radiobuttons as well as, standard Buttons (in case that helps).
You can use update method.
def button_action():
b.config(state='disabled')
b.update() # <----------
# Activate some hardware that takes a few seconds.
b.update() # <----------
b.config(state='normal')
The first call to update is to make the button displayed as disabled state.
The second call to update is to handle all pending event (clicks in your case) before enable the button.
BTW, it's normal state, not enabled that make the button back to normal state.