Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
300 views
in Technique[技术] by (71.8m points)

python - Kivy GUI freezes when sending repeated commands

I have the following code in which I am trying to send time to an Arduino to be displayed on an OLED. the Arduino side works well, if commands are sent individually it will display. However, I want the time to be updated every second. With some tweaking I am able to get it to update ever 2 seconds or so, with sometimes showing two times at once. I tried using threading but I'm not sure if its correct or not. Here is the python script:

    import serial
    import kivy
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.widget import Widget
    from datetime import datetime, timedelta
    import time
    from kivy.clock import Clock
    import threading
    
    ard_connected = False
    
    try:
        ard = serial.Serial(
        port='COM10',
        baudrate = 9600
        )
        ard.flush()
        ard_connected = True
    except:
        print("Arduino Not Connected")
    
    Builder.load_file('Layout.kv')
    
    
    class GUILayout(Widget):
        def ShowTime(self, state):
            threading.Timer(1, self.ShowTime).start()
            now = datetime.now()
            a = timedelta(seconds=1)
            while state == 'down':
                if (ard_connected):
                    current_time = now.strftime("%H:%M:%S")
                    ard.write(current_time.encode())
                    ard.flush()
                    now += a
    
            if (ard_connected):
                ard.write(" ".encode())
                ard.flush()
    
    class GUI(App):
        def build(self):
            updateClock = GUILayout()
            Clock.schedule_interval(updateClock.ShowTime, 0.5)
            return updateClock
    
    if __name__ == '__main__':
        GUI().run()

and the .kv file:

    <GUILayout>
    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height
            
        GridLayout:
            cols: 2
    
            ToggleButton:
                text: "Time"
                on_state: root.ShowTime(self.state)
                backgrund_normal: ""
                background_color: (150/255,150/255,150/255,1)
question from:https://stackoverflow.com/questions/65878007/kivy-gui-freezes-when-sending-repeated-commands

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You have too many things starting the ShowTime() method:

Clock.schedule_interval(updateClock.ShowTime, 0.5)

and

on_state: root.ShowTime(self.state)

and

threading.Timer(1, self.ShowTime).start()

And each of those has the possibility to start an infinite loop (while state == 'down':), since the state variable that is passed into ShowTime() will never change. The loop started by clicking on the ToggleButton will run in the main thread, freezing your GUI.

I believe a better approach would be to just start/stop the ShowTime() method at one location. perhaps using the ToggleButton.

Try changing the kv to accomplish that:

        ToggleButton:
            text: "Time"
            on_state: root.startShowTime(self.state) if self.state == 'down' else root.stopShowTime()
            backgrund_normal: ""
            background_color: (150/255,150/255,150/255,1)

and add/change GUILayout and GUI methods to support that:

class GUILayout(Widget):
    def startShowTime(self, state):
        self.clock_event = Clock.schedule_interval(self.ShowTime, 0.5)

    def stopShowTime(self):
        self.clock_event.cancel()
        if (ard_connected):
            ard.write(" ".encode())
            ard.flush()

    def ShowTime(self, dt):
        if (ard_connected):
            now = datetime.now()
            current_time = now.strftime("%H:%M:%S")
            ard.write(current_time.encode())
            ard.flush()

class GUI(App):
    def build(self):
        updateClock = GUILayout()
        return updateClock

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...