How to click multiple times on QRadioButton but only run function once? - python

I have 2 radio buttons. The first one, radio1, is connected to a function func() and inside this function connects a push button, pushButton, to another function print_me().
This is the code stripped down:
radio = self.dockwidget.radioButton
radio.clicked.connect(func)
def func():
# Connect pushButton to "print_me" function
connect = self.dockwidget.pushButton
connect.clicked.connect(print_me)
def print_me():
print 'Connected'
When the user clicks radio1 and then pushButton, a message is printed. Problem is if the user clicks radio 10 times and then pushButton, the message is also printed 10 times. Or if the user clicks radio1, then radio2, and back to radio1, it will still print the message twice.
Is there a way to prevent this so that it will only print the message once when either radio button is clicked?

Have a global variable and set it to either True or False. Then add an if statement to your code (In this example the global variable name is clicked_radio_button):
radio = self.dockwidget.radioButton
radio.clicked.connect(func)
clicked_radio_button = False #Set global variable
def func():
if clicked_radio_button == False:
# Connect pushButton to "print_me" function
connect = self.dockwidget.pushButton
connect.clicked.connect(print_me)
clicked_radio_button = True #Set global variable to True
else:
pass #Do nothing if already pressed
def print_me():
print 'Connected'

Related

problem rising events with keyboard clicks in PySimpleGUI

I tried to find codes online about rising events in my PySimpleGUI program by simple keyboard clicks like ENTER or Ctrl+A for instance but I couldn't just find any about it, I went to the documentation of PySimpleGUI and didn't shut my tap without learning a thing.
Here is a simple code i wrote:
import PySimpleGUI as sg
layout = [[sg.I(key='In'), sg.B('Ok')],[sg.T(enable_events=True,key='T')]]
win=sg.Window("Keyboard Events", layout)
while True:
event, value= win.read()
#close event
if event == sg.WIN_CLOSED:
break
#greeting evnt
if event in ('Ok'): #( 'OK', 'KEYBOARD ENTER EVENT'):
msg = "Hello "+value['In'] # message to show user
win['T'].update(msg) # show user message
win['In'].update("") # clear input field after submitting
win.close()
What should I say to PySimpleGUI for let it run #greeting event when I press the ENTER key? Can someone help me please? Thanks guys!
Good question! And yes, its the documentation, not you. While this may not answer your question directly, here is some useful information.
You can choose to set return_keyboard_events=True as option when creating the window (sg.Window()). This will return every key hitting an input, as well as some scrolling events, meta keys, and so on.
window.read() returns a tuple (event, values). event can be:
None (sg.WIN_CLOSED)
A string of length one with the key from an input. For example 'a'.
The key of a control. For example, 'Ok'.
A tuple with more information. For example, clicking in a table gives a tuple of (keyname, "+CLICKED+", (row, column)
A special key, such as Return:6033979789 or Meta_L:922810622.
I use this as an alternative to bind_return_key when I might have multiple text entries on the screen:
if isinstance(event, str) and event.startswith('Return'):
event = 'return ' + self.window.find_element_with_focus().key
Also, I find printing to the console is necessary to debug events:
event, values = self.window.read()
print(f" event (type:{type(ui_event)}, {ui_event}, len:({len(ui_event)})"
f" with values {ui_values}")
Option required for element
sg.Input(do_not_clear=False, key='In') clear input field after event
sg.Button('Ok', bind_return_key=True) the return key will cause this button to be pressed
import PySimpleGUI as sg
layout = [[sg.I(do_not_clear=False, key='In'), sg.B('Ok', bind_return_key=True)],[sg.T(enable_events=True,key='T')]]
win=sg.Window("Keyboard Events", layout)
while True:
event, value= win.read()
#close event
if event == sg.WIN_CLOSED:
break
#greeting evnt
if event == 'Ok':
msg = "Hello "+value['In'] # message to show user
win['T'].update(msg) # show user message
win.close()

How can I open multiple popups in succession?

I'm currently working on an application written in Kivy in python.
I have 2 multiprocessing.Processes running:
One is a process for the RFID-reader, I open a popup that lets me choose a screen to go to.
The second process is for Serial communication.
I use queues to communicate with my main thread, and that works great. The problem I'm facing at the moment is I need to introduce a learning process to my Kivy program.
I have 4 screens which I call
mainscreen
adminscreen
managementscreen
initialscreen <- This screen runs only once, once it's set, the screen won't be accessable anymore.
This is the function that gets called when I push the button inside the initialscreen:
def startLearningProcess(self, lockeramount):
self.lockeramount = int(lockeramount)
with Database(self.databasepath) as db:
db.truncate_table('LOCKERS')
# resetting primary key sequence to make the ids start from 1
db.reset_primary_key_sequence('LOCKERS')
for locker in range(int(lockeramount)):
# use a with statement to automatically close the db after the operations
with Database(self.databasepath) as db:
# inserting the given amount lockers to the database as rows.
db.insertLockerRow(locker+1,'Pieter')
if I add the following to the function, 5 popups get opened all at once:
while self.lockeramount != 0:
popup = Popup(title='Test popup', auto_dismiss=True, content=Label(text='Hello world'), size_hint=(None, None), size=(400, 400))
popup.open()
self.lockeramount -= 1
When I input the number 5 into my interface, I want to have 5 popups to open up for me one by one. How can I make it so when I push a button I open up 1 popup, instead of all 5 at once? I apologize for my grammar, english is not my first language.
EDIT:
while John's answer worked perfectly, I was looking for another solution that did not use threading. I solved it by doing the following:
In my class InitialScreen(Screen): I added 2 variables, a bool that starts out with False (booleanUp) and a int variable that starts at 0 (lockeramount).
When I enter my def startLearningProcess I set the lockeramount variable to the number I input into my screen. I added an interval to the startLearningProcess function: Clock.schedule_interval(lambda dt: self.schedule_popups(), 1). I then added the following functions:
def close_popup(self, instance):
self.booleanUp = False
def schedule_popups(self):
if self.lockeramount > 0 and not self.booleanUp:
print(f'opening up popup {self.lockeramount}')
popup = Popup(title='MyPopup', content=Label(text='Abba ' + str(self.lockeramount)), size_hint=(0.5, 0.5))
popup.bind(on_dismiss=self.close_popup)
self.lockeramount -= 1
self.booleanUp = True
popup.open()
else:
print('not opening another popup')
When I open a new popup, I set the boolean to true, so that with the next interval it won't open another interval. I made an on_dismiss event that resets the variable back to False and bound it to my popup.
You can use a Queue to make the Popups wait. Define a custom Popup that accepts a Queue in its __init__() method, and sends something (could even be None) to the Queue when it is dismissed. And your loop can use the Queue to wait for the Popups to be dismissed.
Here is a custom Popup that uses a Queue:
class MyPopup(Popup):
queue = ObjectProperty(None)
def dismiss(self, *_args, **kwargs):
super(MyPopup, self).dismiss(*_args, **kwargs)
if self.queue:
self.queue.put(None)
For this to work, you must run it in another thread. Otherwise, waiting for the Queue on the main thread will never end, because holding the main thread will prevent the Popup from dismissing. Here is some code that shows 5 Popups in succession, one at a time:
def doit(self):
threading.Thread(target=self.popup_thread).start()
def popup_thread(self):
self.queue = Queue()
for i in range(5):
Clock.schedule_once(self.show_popup)
self.queue.get()
def show_popup(self, dt):
popup = MyPopup(title='MyPopup', content=Label(text='Abba ' + str(dt)), size_hint=(0.5, 0.5), queue=self.queue)
popup.open()
To start the Popups, just call the doit() method, probably as an action associated with a Button.

Handling pyTelegramBotAPI floating keyboard value

I'm new on making Telegram chatbot using pyTelegramBotAPI. In this case, i have multiple choices, the 'Trapezoid' and 'Simpson'. Here is the following code
#bot.message_handler(commands=['calculate'])
def welcome(message):
print(message)
markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
markup.add('Trapezoid', 'Simpson')
reply = bot.reply_to(message, "Select computation method" ,reply_markup=markup)
if(reply.text == 'Trapezoid'):
bot.register_next_step_handler(reply, trapezoid_handler)
elif(reply.text == 'Simpson'):
bot.register_next_step_handler(reply, simpson_handler)
def trapezoid_handler(message):
bot.send_message(message.id, "Trapezoid Block")
def simpson_handler(message):
bot.send_message(message.id, "Simpson Block")
Here is a picture when i run the /calculate command
Here is picture when i press the 'Trapezoid' button
As you can see, when i press the 'Trapezoid' button, the trapezoid_handler was not executed.
The goal is, when i press either 'Trapezoid' or 'Simpson' button, it later move to the following button value. Am i access the floating keyboard value correctly? How do i access the floating keyboard value?
Thank you for your respond
Here, it returns reply text (i.e "Select computation method") So you're not getting actual value when you click buttons.
Fixed Code :
#bot.message_handler(commands=['caluculate'])
def welcome(message):
print(message)
markup = types.ReplyKeyboardMarkup(one_time_keyboard=True)
markup.add('Trapezoid', 'Simpson')
reply = bot.reply_to(message, "Select computation method" ,reply_markup=markup)
bot.register_next_step_handler(reply, markup_handler)
def markup_handler(message):
if(message.text == 'Trapezoid'):
bot.send_message(message.chat.id, "Trapezoid Block")
elif(message.text == 'Simpson'):
bot.send_message(message.chat.id, "Simpson Block")

Python GPIO raspberry pi

So bassicaly the user will press the picture_pin buton first, then this calls the picture_taking() function which then it should stop and wait for either (Accept_Pin or Decline_Pin) buttons to be pressed, it should not let the user to continue unless a selection is made. so when the user makes his/her selection then it go back and wait for the picture_pin button. at this stage the Accept_Pin and Decline_Pin should have no affect at all.
I have a python program that waits for a button press from the user then it runs a function to do its thing. what I would like to accomplish is, in that function I would like to also wait for another button press.
(Main.py)
----etc
## PICTURE FUNCTION ##
def picture_taking():
.....etc
returnvalue = subprocess.check_output("sudo ./" + config.layout + ".sh", shell=True)
GPIO.wait_for_edge(Accept_pin, GPIO.FALLING)
GPIO.wait_for_edge(Decline_Pin, GPIO.FALLING)
pad1alreadyPressed = False
pad4alreadyPressed = False
while True:
pad1pressed = not GPIO.input(Accept_pin)
pad4pressed = not GPIO.input(Decline_Pin)
if pad1pressed and not pad1alreadyPressed:
print "Accepted photo:" + str(returnvalue)
pad1alreadyPressed = pad1pressed
if pad4pressed and not pad4alreadyPressed:
print "Declined photo:" + str(returnvalue)
pad4alreadyPressed = pad4pressed
(This here is my Main Program)
#Main section
while True:
time.sleep(0.2)
#camera.hflip = false
camera.shutter_speed = 2000000000
camera.exposure_mode = 'off'
#camera.iso = 1000
camera.preview_fullscreen = True
camera.preview_alpha = 150
camera.start_preview()
GPIO.wait_for_edge(picture_pin, GPIO.FALLING)
picture_taking()
So in the picture_taking() function I would like to ask the user if they accept this picture or not
if they press button (GPIO 19) then they accept or (GPIO 6) as Decline
after they do there selection the program should go back and wait for the main button to select below. and these two buttons should only be selectable inside the function.
I tried this in the Picture_taking() function
when I make the selection it only accepts the "Decline_pin" button, but after I press the "Decline button" then it reads "Accept button".
The other issue is that it does not go back and wait for the Main button "picture_pin" to be pressed. it seems to be stuck here and not exiting.
I am not sure if this is something to do with Indent stuff in Python.
Thank you.
(This should be a comment, not an answer but I don't have reputation 50 yet).
Is this your actual code? I can't understand how it ever returns from the while True: clause in picture_taking(). I'd think you'd need to have something like
while (!(pad1alreadyPressed or pad4alreadyPressed)):

Python: cannot find the handle with win32gui.FindWindowEx()

I'm trying to ge the handle for "Yes" button in a dialog, so I can send the message to click it.
I get the dialog and then I try to find the button, but I always get 0 back.
import win32gui
hwnd = win32gui.FindWindow("#32770", "Programs and Features")
# got back the correct handle to the dialog
win32gui.SetForegroundWindow(hwnd)
btnhdl = win32gui.FindWindowEx(hwnd, 0, "Button", "&Yes")
# returns 0
The button is there and the class and title seem to be ok. I verified it by this:
def printClasses(childHwnd, lparam):
if win32gui.GetWindowText(childHwnd) == "&Yes":
print win32gui.GetClassName(childHwnd), win32gui.GetWindowText(childHwnd)
return 1
win32gui.EnumChildWindows(hwnd, printClasses, None)
# output: Button &Yes
Looks like everything should be fine, but why it doesn't return the handle with FindWindowEx?
Thanks
[From the comments in the OP] Maybe the button is a child of a child, ie a grandchild? IIRC EnumChildWindow enumerates recursively while FindWindowEx does not.

Categories