Clock Schedule Once Error

31 views
Skip to first unread message

Shoumik Das

unread,
Sep 6, 2020, 12:33:44 AM9/6/20
to Kivy users support
I have a class with two functions. One function calls the second with Clock.schedule_once(function_name).

class SivaCEFBrowser(Screen):
def back_to_login(self):
App.get_running_app().root.current='login_screen'
App.get_running_app().root.transition.direction='right'

def go_to_verify(self):
App.get_running_app().root.current='verify_screen'
App.get_running_app().root.transition.direction='left'

def launch_cef_browser(self):
sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error.
cef.Initialize()
cef.CreateBrowserSync(url="https://www.google.com/", window_title="Hello World!")
cef.MessageLoop()
cef.Shutdown()

def trigger_browser(self):
Clock.schedule_once(self.launch_cef_browser)

When my code runs, the trigger_browser() function is called which, in turn, invokes launch_cef_browser(). This is the error that I get:Screenshot from 2020-09-06 10-00-40.png
What am I missing here?

Elliot Garbus

unread,
Sep 6, 2020, 12:40:51 AM9/6/20
to kivy-...@googlegroups.com

When clock call a method it passes in the a time value.  You don’t need to use this value, but you must have the right number of parameters.

 

Change:

def launch_cef_browser(self):

to:

def launch_cef_browser(self, dt):

When my code runs, the trigger_browser() function is called which, in turn, invokes launch_cef_browser(). This is the error that I get:

What am I missing here?

 

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/628ad0b2-baf3-4a54-b135-0cc21492ad3dn%40googlegroups.com.

 

Screenshot from 2020-09-06 10-00-40.png

Shoumik Das

unread,
Sep 6, 2020, 6:42:03 AM9/6/20
to kivy-...@googlegroups.com
Thanks, Elliot. That worked. 😊 I have another question related to the same topic: I actually want to run the launch_cef_browser() method in the background in a separate thread, which is why I used the clock function in the first place.

But, in the present code, the Kivy code execution pauses until the cef browser is closed, which makes me wonder that the clock.schedule_once() statement is not launching the method in a different thread.

How can I make this function call run in a separate thread in the background?

Can you please advise?

Thanks in advance.

Elliot Garbus

unread,
Sep 6, 2020, 10:40:19 AM9/6/20
to kivy-...@googlegroups.com

Here is a simple example using the threading module to create a background thread.  You can start multiple background threads by pressing the ‘Start Background Thread’ button more that once.  The Test button is the foreground task, you can see the UI remains interactive.

 

In addition to the python docs, there are examples of the threading module: https://pymotw.com/3/threading/index.html

 

 

 

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button

import threading
import time

kv =
"""
BoxLayout:
    orientation: 'vertical'
    Label:
        text: 'Threading Test'
    Button:
        text: 'Test Button'
        on_release: print('Test Button Pressed')
    ThreadButton:
        text: 'Start Background Thread'
        on_release: self.start_thread()
"""


class ThreadButton(Button):
   
def __init__(self, **kwargs):
       
super().__init__(**kwargs)
       
self.t = None

    def
start_thread(self):
       
print('Starting background thread')
       
self.t = threading.Thread(target=self.print_and_sleep)
       
self.t.start()

   
@staticmethod
   
def print_and_sleep():  # static methods do not use the self object
       
i = 0
       
while i < 20:
           
print(f'Useless background thread printing a count {i}')
            i +=
1
           
time.sleep(.5)
       
print('Background Thread Completed')


class ThreadTestApp(App):
   
def build(self):
       
return Builder.load_string(kv)


ThreadTestApp().run()

Thanks in advance.

What am I missing here?

 

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/628ad0b2-baf3-4a54-b135-0cc21492ad3dn%40googlegroups.com.

 

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/5f546847.1c69fb81.60827.bca5SMTPIN_ADDED_MISSING%40gmr-mx.google.com.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

Robert Flatt

unread,
Sep 6, 2020, 1:04:16 PM9/6/20
to Kivy users support
which makes me wonder that the clock.schedule_once() statement is not launching the method in a different thread.

Each tick of the Kivy event loop is in the same thread.
Clock.sechedule()  just schedules an event for a future iteration of the loop.
Thanks in advance.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Shoumik Das

unread,
Sep 8, 2020, 6:46:57 AM9/8/20
to Kivy users support
Thanks, Elliot. I managed to trigger the cefpython browser in a separate thread as shown below. But I noticed that the thread does not exit on its own and continues to run in the background although it does not stop the execution of the Kivy app. As a result, if I click on the same button again, a new browser window does not open. Is there a way to close the current browser thread as soon as the associated window is closed?

Code

class SivaCEFBrowser(Screen):
def back_to_login(self):
App.get_running_app().root.current='login_screen'
App.get_running_app().root.transition.direction='right'

def go_to_verify(self):
App.get_running_app().root.current='verify_screen'
App.get_running_app().root.transition.direction='left'

def launch_cef_browser(self): # Use an additional parameter, 'dt', if invoked using Clock.schedule_once().
sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error.
cef.Initialize()
cef.CreateBrowserSync(url="https://www.google.com/", window_title="Hello World!")
cef.MessageLoop()
cef.Shutdown()

def trigger_browser(self):
#Clock.schedule_once(self.launch_cef_browser) # Starts in the same thread and pauses execution of Kivy code.
self.t=threading.Thread(target=self.launch_cef_browser)
self.t.start()

Screenshots

Browser is invoked successfully in a separate thread and the app proceeds to the next screen.

Screenshot from 2020-09-08 16-11-24.png

Now, when I close the browser window, its thread still seems to be running. This does not let me invoke a new browser window again. I want to kill the browser's thread once the window is closed. I was going trhough the article that you shared and came across a statement called t.join() for terminating a session but I am not sure how to use it. Can you please advise?

Screenshot from 2020-09-08 16-13-50.png

Thanks as always for your help and advice.

Elliot Garbus

unread,
Sep 8, 2020, 9:34:09 AM9/8/20
to kivy-...@googlegroups.com

In threading, you want the thread to complete.   Join alone will not do what you want.  Join waits for the thread to complete.  Imagine you had spawned a thread to do a task, and you wanted to wait until it was complete… then it would join the main thread.

 

I’m not familiar with the python cef browser, but looking at your code below I have a suggestion.

My expectation is that in the launch_cef_browser() method, the browser enters the MessageLoop(), and never returns, so Shutdown does not get called.

Use the screen event on_leave to shutdown the browser.  I expect this would cause the MessageLoop to return, and the thread to complete.

 

def on_leave(self, *args):

    cef.Shutdown()

 

Taking a quick look at the PythonCEF documents, perhaps you should call QuitMessageLoop()… you want to get the thread to complete.

 

From: Shoumik Das
Sent: Tuesday, September 8, 2020 3:47 AM
To: Kivy users support
Subject: Re: [kivy-users] Clock Schedule Once Error

 

Thanks, Elliot. I managed to trigger the cefpython browser in a separate thread as shown below. But I noticed that the thread does not exit on its own and continues to run in the background although it does not stop the execution of the Kivy app. As a result, if I click on the same button again, a new browser window does not open. Is there a way to close the current browser thread as soon as the associated window is closed?

 

Code

 

class SivaCEFBrowser(Screen):

               def back_to_login(self):

                              App.get_running_app().root.current='login_screen'

                              App.get_running_app().root.transition.direction='right'

 

               def go_to_verify(self):

                              App.get_running_app().root.current='verify_screen'

                              App.get_running_app().root.transition.direction='left'

 

               def launch_cef_browser(self): # Use an additional parameter, 'dt', if invoked using Clock.schedule_once().

                              sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error.

                              cef.Initialize()

                              cef.CreateBrowserSync(url="https://www.google.com/", window_title="Hello World!")

                              cef.MessageLoop()

                              cef.Shutdown()

 

               def trigger_browser(self):

                              #Clock.schedule_once(self.launch_cef_browser) # Starts in the same thread and pauses execution of Kivy code.

                              self.t=threading.Thread(target=self.launch_cef_browser)

                              self.t.start()

 

Screenshots

 

Browser is invoked successfully in a separate thread and the app proceeds to the next screen.

 

 

Now, when I close the browser window, its thread still seems to be running. This does not let me invoke a new browser window again. I want to kill the browser's thread once the window is closed. I was going trhough the article that you shared and came across a statement called t.join() for terminating a session but I am not sure how to use it. Can you please advise?

 

Screenshot from 2020-09-08 16-13-50.png
Screenshot from 2020-09-08 16-11-24.png

Elliot Garbus

unread,
Sep 8, 2020, 9:41:53 AM9/8/20
to kivy-...@googlegroups.com

Reading the PythonCEF docs, to looks like calling QuitMessageLoop() is the right way to go.

https://github.com/cztomczak/cefpython/blob/master/api/cefpython.md#quitmessageloop

 

class SivaCEFBrowser(Screen):

    def on_leave(self, *args):

        cef.QuitMessageLoop()

Shoumik Das

unread,
Sep 13, 2020, 2:31:14 PM9/13/20
to Kivy users support
Hi Elliot. Sorry for the delayed response. Thanks again for the suggestion. I am able to quit the thread successfully. However, it still does not get me the required behaviour. The browser launches correctly at the first instance. If I close it and try to re-launch it by clicking on the launch button, it throws the following error:

AssertionError: cefpython.CreateBrowserSync() may only be called on the UI thread

Sometimes, the Kivy app crashes with the following error:

Trace/breakpoint trap (core dumped)

I know this may not be the right forum to ask questions about cefpython browser integration with Kivy but I really need to implement a browser function for my app. If I am not able to get cefpython working, can you recommend any other browser framework which I may embed in my Kivy app? I used the webbrowser.open(redirect_url, new=2) option in Python and it works fine on Linux but I am looking to make it work on Android as well and a lot of users have reported that it does not work on Android. Hence, I thought a single consistent platform-independent framework such as cefpython might help.

Please suggest.

Thanks as always for your help.

Elliot Garbus

unread,
Sep 13, 2020, 3:10:42 PM9/13/20
to kivy-...@googlegroups.com

I’ve not done any work on Android – perhaps Robert has an idea.

 

One thought:

  • The fact that it works once, and the fails suggest there might be an issue with the way the browser is shutting down.  Make sure you are closing down the cfepython browser correctly.  There is a cfebrowser method shutdown().  Call shurdown() after you have exited the message loop.

Code

 

Now, when I close the browser window, its thread still seems to be running. This does not let me invoke a new browser window again. I want to kill the browser's thread once the window is closed. I was going trhough the article that you shared and came across a statement called t.join() for terminating a session but I am not sure how to use it. Can you please advise?

 

 

Thanks as always for your help and advice.

Robert Flatt

unread,
Sep 13, 2020, 4:58:01 PM9/13/20
to Kivy users support
Here is a web browser that is called from Kivy on Android.
It is full screen only, I didn't try switching back to the Kivy view.
See the reference for more details, this is all I got.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from jnius import autoclass
from android import mActivity
from android.runnable import run_on_ui_thread

'''
Reference:
https://groups.google.com/forum/?oldui=1#!topic/kivy-users/9sH0y3KxCuU

buildozer.spec:
android.permissions = INTERNET
'''


WebView = autoclass('android.webkit.WebView')
WebViewClient = autoclass('android.webkit.WebViewClient')

# See https://github.com/kivy/python-for-android/issues/1908
@run_on_ui_thread  
def create_webview(*args):
    webview
= WebView(mActivity)
    webview
.getSettings().setJavaScriptEnabled(True)    
    wvc
= WebViewClient()
    webview
.setWebViewClient(wvc)
    mActivity
.setContentView(webview)
    webview
.loadUrl('https://www.google.com')

class Wv(Widget):
   
def __init__(self, **kwargs):
       
super().__init__(**kwargs)
       
Clock.schedule_once(create_webview, 0)

class WvDemo(App):
   
def build(self):
       
return Wv()

WvDemo().run()

Shoumik Das

unread,
Sep 13, 2020, 10:28:39 PM9/13/20
to kivy-...@googlegroups.com
Thanks Robert! I shall try this out immediately and share the results in this forum.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages