I'm having this issue where my GUI program calls another class repeatedly (say 5 times a second), it calls class.Process(). I also have buttons that call class.Process() and the gentlemen who gave me the code for the class.Process() says that when I have the two operating at once (repeatedly calling and buttons) they could overlap and cause errors. Is there a way around this so I don't have a possible 'double-call' of Process()?
thread = threading.Thread(target=self.run,args=()) \
thread.daemon = True \
thread.start()
def run(self):
self.T.insert(END,'\n')
self.T.insert(END,'\n')
while True:
boolean = self.shutterclass.IsIdle()
while not boolean:
self.shutterclass.Process()
message = self.shutterclass.GetStatusMsg()
if message:
self.T.insert(END,message)
self.T2.insert(END,message)
t.sleep(0.2)
The above code calls the function repeatedly and the below code is a sample of a button press.
def isclicked(self,FPress,HPress,QBPress,SPress,EPress,JDPress,JCPress):
'''Function to tell if a button is pressed.'''
if FPress == True:
now = datetime.now()
self.shutterclass.Process(command = 'FIRE')
self.T.insert(END,"\n" + now.strftime("%H:%M:%S"))
self.T.insert(END,'\n' + 'Command: FIRE')
self.T2.insert(END,"\n" + now.strftime("%H:%M:%S"))
self.T2.insert(END,'\n' + 'Command: FIRE')
self.T.insert(END, "\n" + f"{self.shutterclass.GetStatusMsg()}")
You could make it so that instead of doing the call to Process in the while loop, you call the button press event instead. That way both user input and program call go through the button press method. Then if the button press method does not have any inherent state, you could possibly avoid any clashes due to instances of the button object.
From what I can tell, the thread automatically calls the shutterclass. Process when it is idle, I will assume that means the user is not having any input in that object? But then you call the process method, which will change it's status and so the while loop will evaluate to true. One way to fix this could be to put the isIdle status of the shutter class into a different memory object, which will implement a semaphore. That way the callers of that resource will have to queue up in order to modify it, thus making it less probably that they both access it simultaneously.
Related
I am trying to write a CUI app where the window is supposed to flash after returning from a customized infunction. This would make it so that the flashing occurs after the input prompt is displayed, not beforehand.
My first idea was:
from ctypes import windll
def custom_formatted_input():
while get_foreground_window_title() != "cmd.exe":
windll.user32.FlashWindow(windll.kernel32.GetConsoleWindow(), True)
time.sleep(0.5)
return input(f"""{time.strftime("%Y-%m-%d %H:%M:%S")}{"".ljust(4)}[INPUT]{"".ljust(6)}{message} """)
where get_foreground_window_title is a Windows API call through ctypes.
This works, however this makes it so the input prompt is displayed whenever the flashing stops, i.e. after the user activates the cmd window.
How can I make it so that this flashing happens after the input function returns? I believe this would entail a decorator, however I couldn't figure the solution out on my own. Thanks!
Figured it out! Since execution always stops whenever input() is called, the flashing needs to occur while the execution is stopped, i.e. on another thread.
Code:
def flash_window():
while "cmd.exe" not in get_foreground_window_title():
windll.user32.FlashWindow(windll.kernel32.GetConsoleWindow(), True)
time.sleep(0.5)
def input_log(message):
t1 = threading.Thread(target=flash_window)
t1.start()
return input(f"""{time.strftime("%Y-%m-%d %H:%M:%S")}{"".ljust(4)}[INPUT]{"".ljust(6)}{message} """)
I need my win.flip() call as much close to being real-time as possible. Meanwhile, while waiting for the trigger to occur, which flips the buffer, I also want some keyboard keypresses to be listened for. So, which one is faster:
assigning event.globalKeys.add() and relying on pyglet's thread to poll it
or manually checking for len(event.getKeys()) in my trigger callback?
You should be using the new Keyboard class which can plug into either the ioHub event polling system or the Psychtoolbox engine for event polling. Both of those poll the keyboard on a separate process independent of the rendering loop and timestamp the keypresses at source. Calls to event.getKeys() use pyglet and then polling occurs only once per screen refresh, at least during dynamic updating.
We would typically recommend, however, that you simply create studies in the Builder which will automatically use the current best practice and methods so you don't have to keep abreast of what the latest recommendations are.
at first implemented the same with infinite while True loop listening for key that will never be pressed - just to make globalKeys constantly active, but then realised event.waitKeys will be polling during all my experiment - which i do not want
so, i made a function instead which will be checking all my global keys and calling related functions of my experiment when needed, and there will be len(event.getKeys()) in some places inside them, when i want a possibility to suspend the procedure
def my_fun():
while trigger == False:
#doing main experiment functionality
if len(event.getKeys()):
listen_for_keypresses()
return
def listen_for_keypresses():
print('...ready for input')
keys_pressed = event.waitKeys(clearEvents=False)
if 'escape' in keys_pressed[0]:
input_pressed = input('Confirm exit y/n')
if input_pressed == 'y':
win.close()
logging.flush()
io.quit()
core.quit()
return
elif 'r' in keys_pressed[0]:
my_fun()
return
listen_for_keypresses()
return
listen_for_keypresses()
I have a problem with my Tkinter window crashing due to the usage of the 'sleep' function in the code below.
The programm in the background works just fine, even if the window crashed a long time ago.
How can I use functions like time.time to ensure that I don't make queries to the API too frequently rather than making a blocking call to time.sleep.
In other words, once I follow a list of new users, how do I prevent the program from making another request in the next 30 seconds?
def follow_users(self,users_list):
api = self.api
api.login()
api.getSelfUsersFollowing()
result = api.LastJson
for user in result['users']:
following_users.append(user['pk'])
for user in users_list:
if not user['pk'] in following_users:
print('Following #' + user['username'])
api.follow(user['pk'])
# set this really long to avoid from suspension
sleep(30)
else:
print('Already following #' + user['username'])
sleep(15)
def unfollow_users(self):
api = self.api
api.login()
api.getSelfUserFollowers()
result = api.LastJson
for user in result['users']:
follower_users.append({'pk':user['pk'], 'username':user['username']})
api.getSelfUsersFollowing()
result = api.LastJson
for user in result['users']:
following_users.append({'pk':user['pk'],'username':user['username']})
for user in following_users:
if not user['pk'] in follower_users:
print('Unfollowing #' + user['username'])
api.unfollow(user['pk'])
sleep(20)
# set this really long to avoid from suspension
I would start by writing a function that follows a single user, and nothing more. It doesn't need to loop over a list or sleep or anything like that, it should just follow that one user.
For example:
def follow_user(self, user):
... code to follow this user ...
Next, define a function that pulls one user off of a list, calls the follow_user function, and then re-schedules itself to run again after a timeout.
The following example assumes there's a global variable named root which represents the root window, but you can use any widget you want. It also assumes that the class maintains a list of users to be followed in an instance variable named self.users.
def follow_users(self):
if self.users:
user = self.users.pop()
self.follow_user(user)
root.after(30000, self.follow_users)
Then, once your program starts, call this function exactly once. It will call itself once every 30 seconds. If there is at least one user in self.users it will pull it from the list and follow the user. 30 seconds later it will do it again, and then again, and so on. You can update self.users whenever you want and that user will eventually get followed.
Back after another 30 minute search and either failure to comprehend results or unable to find results...
I want to force my application to wait for a button click before continuing, and have the following code snippet as my example:
...
def crack(self, Filenamelist, forceclick):
forceclick += 1
self.crackButton.configure(state='active')
if forceclick != 2:
self.crackButton.bind('<ButtonRelease-1>', self.crack(Filenamelist, forceclick))
self.outputBox.insert(END, '\n' + 'Parsing answer numerator...' + '\n')
...
I basically want it to load the function crack(), increment 1 to forceclick (which was set to 0 beforehand), change the 'crack button' to an active state, and then bind the button while waiting for the user to provoke the bind. After the bind is provoked, the function reloads, increments one to forceclick, and then skips the if statement.
However, when I run the program through, it just binds the key to the crack button and automatically reloads the function to bypass the if statement... I tried a while loop before, but that did not end well...
Any suggestions?
You need to make the bound function a lambda:
self.crackButton.bind('<ButtonRelease-1>', lambda e: self.crack(Filenamelist, forceclick))
Currently it is calling the function.
Although there are probably better ways to do what you are trying to accomplish, this should fix your immediate issue.
I'm trying to write a GUI program grabbing specific contents from a webpage. The idea is when I hit the start button, the program should start extracting information from that page. And I want to add some code to check if connected to the Internet. If not, continue trying until connected.
So I just added the following code in the event, but found it didn't work. Also the whole program has to be closed in a forced way. Here's my code:
import urllib2
import time
InternetNotOn = True
while InternetNotOn:
try:
urllib2.urlopen("http://google.com")
InternetNotOn = False
print "Everyting is fine!"
except urllib2.URLError, e:
print "Error!"
time.sleep(10)
What could the problem be?
When you have an event based program, the overall flow of the program is this:
while the-program-is-running:
wait-for-an-event
service-the-event
exit
Now, lets see what happens when service-the-event calls something with a (potentially) infinite loop:
while the-program-is-running:
wait-for-an-event
while the-internet-is-on:
do-something
exit
Do you see the problem? In the worse case your program may never call wait-for-an-event again because your loop is running.
Remember: the event loop is already an infinite loop, you don't need to add another infinite loop inside of it. Instead, take advantage of the existing loop. You can use wx.CallAfter or wx.CallLater to call a method which will cause your function to be called at the next iteration of the event loop.
Then, within your function you call wx.CallAfter or wx.CallLater again to cause it to again be called on the next iteration of the event loop.
Instead of time.sleep(10) you can call wxApp::Yield and time.sleep(1) ten times.
Beware of reentrancy problems (e.g. pressing the start button again.). The start button could be dimmed while in the event handler.
But Bryan Oakley's solution is probably the better way.