简体   繁体   English

问:在 Kivy 中替代 Clock.schedule_interval

[英]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.

相关问题 Kivy - 试图理解 Clock.schedule_interval - Kivy - Trying to Understand Clock.schedule_interval AttributeError: 'NoneType' object 在调用 Clock.schedule_interval function 时在 Kivy 中没有属性 'ids' - AttributeError: 'NoneType' object has no attribute 'ids' in Kivy when Clock.schedule_interval function is called 如何在Kivy中使用Clock.schedule_interval更新按钮的文本? - How to update a button's text using Clock.schedule_interval in kivy? 如何在Kivy应用程序中同时运行Clock.schedule_interval实例? - How can I run simultaneous instances of Clock.schedule_interval in kivy app? 如何通过Clock.schedule_interval更改标签文本 - How to change Label text via Clock.schedule_interval 使用Clock.schedule_interval每秒更新一次显示的变量 - Updating a displayed variable every second with Clock.schedule_interval clock.schedule_interval() 在 pygame 中有效还是仅在 pygame 零中有效? - Is clock.schedule_interval() valid in pygame or only pygame zero? 我尝试使用 datetime 和 Clock.schedule_interval 方法制作秒表来打印倒计时,但由于某种原因它不起作用 - I tried making a stop watch using datetime and the Clock.schedule_interval method to print the count down but for some reason it isn't working kivy python时钟时间表更新 - kivy python clock schedule update Kivy 需要时钟时间表的 ID - Kivy IDs needing a clock schedule
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM