[英]Q: Alternative to Clock.schedule_interval in Kivy
I have a separate process parallel to my Kivy app and I am checking a status of shared multiprocessing value using Clock.schedule_interval.我有一个与我的 Kivy 应用程序并行的单独进程,我正在使用 Clock.schedule_interval 检查共享多处理值的状态。
# call the method every second
Clock.schedule_interval(self.callback_status, 1)
When the main thread in Kivy is busy doing something else eg a loop or showing a popup, the checking is interrupted.当 Kivy 中的主线程忙于做其他事情时,例如循环或显示弹出窗口,检查被中断。 Is there an alternative to Clock.schedule_interval?
Clock.schedule_interval 有替代方案吗? Can Kivy manage a background process without queues, pipes or else?
Kivy 可以管理没有队列、管道或其他的后台进程吗?
ps A minimalistic working example would still be too much so for a taste is just the callback method: ps 一个简约的工作示例仍然太多,所以只是回调方法:
@mainthread
def callback_status(self, dt):
global v
try:
if v.value == 1:
# do something
else:
# do something else
except Exception as e:
print(e)
################### UPDATE N.1 ###################### ################### 更新 N.1 #####################
As suggested I run a thread for checking the shared value.正如建议的那样,我运行一个线程来检查共享值。 I have to comment out
@mainthread
for def pin_check(self)
otherwise the main thread remains blocked in the infinite loop not allowing the graphical part to perform its tasks.我必须为
def pin_check(self)
注释掉@mainthread
,否则主线程在无限循环中保持阻塞,不允许图形部分执行其任务。 This approach works well till there are no other threads executed simultaneously.这种方法效果很好,直到没有其他线程同时执行。 Then the checking is interrupted.
然后检查被中断。
@mainthread
def callback_status(self, dt):
# run the checking in a thread
t = threading.Thread(target = self.pin_check)
t.setDaemon(True)
t.start()
# @mainthread # if left uncommented it blocks the main thread
def pin_check(self):
# checking the shared multiprocess value
global v # shared value
try:
while True:
if v.value == 1:
try:
self.alert()
except Exception as e:
print("error 1", e)
break
else:
pass
except Exception as e2:
print("error 2", e)
pass
@mainthread
def alert(self):
print("do something here")
When the main thread in Kivy is busy doing something else eg a loop or showing a popup, the checking is interrupted.
当 Kivy 中的主线程忙于做其他事情时,例如循环或显示弹出窗口,检查被中断。 Is there an alternative to Clock.schedule_interval?
Clock.schedule_interval 有替代方案吗?
Normally best practice would be to do the opposite, don't block the main loop and instead do any long-running work in a thread.通常最好的做法是做相反的事情,不要阻塞主循环,而是在线程中做任何长时间运行的工作。
You could also do the work from your question in a thread, but if it isn't a long-running operation I'd be more inclined to keep it in the main thread and fix whatever is blocking your clock.你也可以在一个线程中完成你的问题,但如果它不是一个长时间运行的操作,我更倾向于将它保留在主线程中并修复任何阻塞你时钟的东西。
Can Kivy manage a background process without queues, pipes or else?
Kivy 可以管理没有队列、管道或其他的后台进程吗?
This doesn't really have anything to do with Kivy, you can use whatever threading and subprocessing you like with all the normal advantages and disadvantages.这与 Kivy 没有任何关系,您可以使用您喜欢的任何线程和子处理,并具有所有正常的优点和缺点。
I have a kivy application that has 2 multiprocessing.Process scripts that both handle their own task.我有一个 kivy 应用程序,它有 2 个 multiprocessing.Process 脚本,它们都处理自己的任务。 An example is my script for reading an RFID-card:
一个例子是我读取 RFID 卡的脚本:
import evdev
from evdev import InputDevice, categorize, ecodes
import multiprocessing
class RFID(multiprocessing.Process):
'''
This class handles the communication with the RFID-scanner and puts every scan in a queue.
This queue can be consumed anywhere in the application.
'''
def __init__(self, rfid_queue, configuration):
multiprocessing.Process.__init__(self)
self.configuration = configuration
self.inputdevice = self.configuration.get_value('RFID', 'inputdevice')
self.device = InputDevice(self.inputdevice) # Calling the InputDevice the RFID-scanner is connected to
self.rfid_queue = rfid_queue # Calling the queue from the constructor
# Normal ASCII lookup table (without caps)
self.scancodes = {
0: None, 1: u'ESC', 2: u'1', 3: u'2', 4: u'3', 5: u'4', 6: u'5', 7: u'6', 8: u'7', 9: u'8',
10: u'9', 11: u'0', 12: u'-', 13: u'=', 14: u'BKSP', 15: u'TAB', 16: u'q', 17: u'w', 18: u'e', 19: u'r',
20: u't', 21: u'y', 22: u'u', 23: u'i', 24: u'o', 25: u'p', 26: u'[', 27: u']', 28: u'CRLF', 29: u'LCTRL',
30: u'a', 31: u's', 32: u'd', 33: u'f', 34: u'g', 35: u'h', 36: u'j', 37: u'k', 38: u'l', 39: u';',
40: u'"', 41: u'`', 42: u'LSHFT', 43: u'\\', 44: u'z', 45: u'x', 46: u'c', 47: u'v', 48: u'b', 49: u'n',
50: u'm', 51: u',', 52: u'.', 53: u'/', 54: u'RSHFT', 56: u'LALT', 57: u' ', 100: u'RALT'
}
# Caps ASCII lookup table
self.capscodes = {
0: None, 1: u'ESC', 2: u'!', 3: u'@', 4: u'#', 5: u'$', 6: u'%', 7: u'^', 8: u'&', 9: u'*',
10: u'(', 11: u')', 12: u'_', 13: u'+', 14: u'BKSP', 15: u'TAB', 16: u'Q', 17: u'W', 18: u'E', 19: u'R',
20: u'T', 21: u'Y', 22: u'U', 23: u'I', 24: u'O', 25: u'P', 26: u'{', 27: u'}', 28: u'CRLF', 29: u'LCTRL',
30: u'A', 31: u'S', 32: u'D', 33: u'F', 34: u'G', 35: u'H', 36: u'J', 37: u'K', 38: u'L', 39: u':',
40: u'\'', 41: u'~', 42: u'LSHFT', 43: u'|', 44: u'Z', 45: u'X', 46: u'C', 47: u'V', 48: u'B', 49: u'N',
50: u'M', 51: u'<', 52: u'>', 53: u'?', 54: u'RSHFT', 56: u'LALT', 57: u' ', 100: u'RALT'
}
self.resultstring = '' # Empty String
self.capsLock = False # Caps check for the ASCII lookup table
self.device.grab() # Reserve the device for exclusive access
def run(self):
for event in self.device.read_loop():
if event.type == ecodes.EV_KEY:
data = categorize(event) # Save the event to inspect it later
# ------------------ Capslock check ------------------
if data.scancode == 42:
if data.keystate == 1:
self.capsLock = True
if data.keystate == 0:
self.capsLock = False
# ------------------ Capslock check ------------------
# ------------------ Decode and add to empty resultstring ------------------
if data.keystate == 1: # Down events only
# if the scanned item is in capslock, get data from the capslock lookup table
if self.capsLock:
key_lookup = u'{}'.format(self.capscodes.get(data.scancode)) or u'UNKNOWN:[{}]'.format(data.scancode) # Lookup or return UNKNOWN:XX
# if the scanned item is not in capslock, get data from the normal lookup table
else:
key_lookup = u'{}'.format(self.scancodes.get(data.scancode)) or u'UNKNOWN:[{}]'.format(data.scancode) # Lookup or return UNKNOWN:XX
# check if data is not an LSHFT (left shift) OR CRLF (linebreak)
if data.scancode != 42 and data.scancode != 28:
# add the key that has been looked up from the lookup table to the resultstring
self.resultstring += key_lookup
if data.scancode == 28:
# if there's a linebreak, add the resultstring to the queue.
self.rfid_queue.put(self.resultstring)
# empty the resultstring for the next RFID scan
self.resultstring = ''
# ------------------ Decode and add to empty resultstring ------------------
In the mainthread I use the following to start a process using the following:在主线程中,我使用以下内容来启动一个进程:
rfidThread = RFID(rfid_queue, configuration)
rfidThread.daemon = True
rfidThread.start()
using a consumer function I pop scanned RFID-cards from the queue in my mainthread like so:使用消费者 function 我从主线程的队列中弹出扫描的 RFID 卡,如下所示:
def check_rfid_scan(self, scannedRFID):
with Database(self.databasepath) as db:
data = db.return_all_from_table('USERS')
uids = db.return_known_UIDs('USERS')
uids = ['.'.join(i) for i in uids]
if scannedRFID in uids and self.rfidqueue is False:
index = uids.index(scannedRFID)
uid, user, permission = data[index]
self.rfidqueue = True
if permission == 1:
self.popup = AdminPopup()
self.popup.value.text = str(user + f' ({self.permissionCheck(permission)})')
print(f'Popup geopend: {self.popup.value.text}')
self.popup.bind(on_dismiss = self.dismissPopupEvent)
self.popup.open()
elif permission == 2:
self.popup = ManagerPopup()
self.popup.value.text = str(user + f' ({self.permissionCheck(permission)})')
print(f'Popup geopend: {self.popup.value.text}')
self.popup.bind(on_dismiss = self.dismissPopupEvent)
self.popup.open()
elif permission == 3:
self.popup = UserPopup()
self.popup.value.text = str(user + f' ({self.permissionCheck(permission)})')
print(f'Popup geopend: {self.popup.value.text}')
self.popup.bind(on_dismiss = self.dismissPopupEvent)
self.popup.open()
else:
if self.invalid is False and self.rfidqueue is False:
self.invalid = True
self.invalidpopup = RFIDInvalidPopup()
print('Invalid popup geopend')
self.invalidpopup.bind(on_dismiss = self.dismissInvalidPopupEvent)
self.invalidpopup.open()
This consumer function gets initialized using:此消费者 function 使用以下命令进行初始化:
Clock.schedule_interval(lambda dt: self.checkRFIDQueue(), 0.5)
I open a popup, check the permission of the user in the database and open a popup according to the permission.我打开一个弹窗,检查数据库中用户的权限,根据权限打开弹窗。 So my main means of interacting with the main thread is using queues between the process and the python application.
所以我与主线程交互的主要方式是在进程和 python 应用程序之间使用队列。 It does use schedule_interval, but I find this the best solution for MY problem.
它确实使用了 schedule_interval,但我发现这是我的问题的最佳解决方案。 I don't know if you can use this, but if it helped give me an upvote:)
我不知道你是否可以使用它,但如果它有助于给我一个支持:)
EDIT: only just noticed this was a question from last year, but will keep this posted.编辑:只是注意到这是去年的一个问题,但会保持发布。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.