Blocking Popup Support?

615 views
Skip to first unread message

Tysen Moore

unread,
Jul 2, 2014, 4:17:01 PM7/2/14
to kivy-...@googlegroups.com
I have a use case where I want to create a popup for some user input while loading a file of data (among other similar use cases).  The problem is the popup is not blocking.  It is modal, but the open() call is not blocking.  Therefore I run into all kinds of problems because the parsing of my data continues even thought it needs user input to proceed properly.  Because there are numerous places where I need this functionality the tear up and complexity added in attempting to serialize these use cases with a non-blocking open() makes it very difficult.

Is there a way to implement a popup.open() that blocks execution?  I realize this could be difficult because we can't block the Kivy main loop.  Has anyone done this? Or is it available? Or have I just missed something?

My simple test with some code taken from the ModalView documentation is below.  I've also tried with a Popup instead of a ModalView and get the same results--as you might expect.

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.modalview import ModalView
from kivy.clock import Clock
from kivy.uix.label import Label

class TestApp(App):

   
def build(self):
        root
= BoxLayout(orientation='vertical')
       
Clock.schedule_once(self._init, 2) # popup after some time
       
return root

   
def my_callback(self, instance):
       
print('ModalView', instance, 'is being dismissed, but is prevented!')
       
return True

   
def _init (self, dt):
        view
= ModalView(size_hint=(None,None), size=(200,75))
        view
.add_widget(Label(text='Hello world'))
        view
.bind(on_dismiss=self.my_callback)
        view
.open()
       
print "***** END *****"

TestApp().run()

Note: the print after the open is displayed while the popup is open which is not what I'd like.  I'd like the print to occur only after the dialog is dismissed.

Alexander Taylor

unread,
Jul 2, 2014, 4:25:35 PM7/2/14
to kivy-...@googlegroups.com
I'm not aware of a way to do this. You generally instead want to split your calculation into two parts, the first leading up to the popup opening, and the second called by the popup when it's finished with (which could be in a range of ways, up to you). This has come up before in (for example) the SO question at https://stackoverflow.com/questions/21894192/creation-of-an-input-dialog-using-kivy

Tysen Moore

unread,
Jul 2, 2014, 4:56:21 PM7/2/14
to kivy-...@googlegroups.com
Thanks for the suggestion.  I've thought of this too.  This is what I referred to as "serializing" my use cases or operations.  This is very messy because of the number of different places involved and complicated by the fact they are nested in for loops, etc.  This serializing is a rather big tear up that I'd like to avoid.  Thanks again for the the link and the suggestion.


--
You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/6tbZl9VCccs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

ZenCODE

unread,
Jul 3, 2014, 12:56:32 AM7/3/14
to kivy-...@googlegroups.com
That's an interesting one. Is it essential to do all the work in one sweep? Could you not do an initial parse to gather data, then do the popup, then do another parse to apply the gathered user input? Kind like how encoding tools do an analysis before they begin the actual encoding?

Tysen Moore

unread,
Jul 3, 2014, 7:11:17 AM7/3/14
to kivy-...@googlegroups.com
One use case is that I've loaded a YAML file of saved data, then I iterate over various portions of the imported data to validate and merge the imported data into my current internal structures.  The validation and merge process each has a number of loops and nested loops to get the work done.  One example is where I iterate over a portion of the structure and throw up a warning popup that I've created in some situations.  These are valid warnings but I've added a "Skip other similar warnings" checkbox.  To support a "skip checkbox" I'd need to track a list of popups and dismiss the rest.  Worse yet is the fact that the parsing continues even though in some situations I need user interaction before proceeding (e.g. during my merge conflict resolution).  So, yes of course I can break this into a *bunch* of smaller functions and serialize the processing. So basically the current code would be split into functions for the contents of each for loops, then one for the loop itself, etc.  So it is possible to refactor the code but I was hoping to avoid this due to the fact that the code will become less readable, harder to follow and harder to maintain due to the number of tiny functions that do very little for the sake of serializing the process.

Is there possibly a way to sit in a loop processing the touch events, ignoring others for just the popup and when I detect a button press or cancel then allow processing to continue?  I haven't dug into this thought yet currently just a half baked thought.  


On Thu, Jul 3, 2014 at 12:56 AM, ZenCODE <zenkey....@gmail.com> wrote:
That's an interesting one. Is it essential to do all the work in one sweep? Could you not do an initial parse to gather data, then do the popup, then do another parse to apply the gathered user input? Kind like how encoding tools do an analysis before they begin the actual encoding?

--

Alexander Taylor

unread,
Jul 3, 2014, 10:56:17 AM7/3/14
to kivy-...@googlegroups.com
I think you could probably implement the way other toolkits probably do it, by making a function that internally spins a while loop until some condition is met (mostly sleeping of course, not just repeatedly checking). Then you could run your calculations in a thread, and call that function when you want to wait.

ZenCODE

unread,
Jul 3, 2014, 2:11:47 PM7/3/14
to kivy-...@googlegroups.com
Yes, what Alexander said. As a variation on that idea, that loop could wait on a flag which you could set externally. Something like

class Waiter(object):
    wait
= True

   
@staticmethod
   
def return_when_done():
       
Waiter.wait = True
       
while Waiter.wait:
            sleep
(0.25)

Keep in mind that this will block the thread, so you will need to do your parsing on a different thread, So, create the popup in a new thread, and after its done, so.

    #create popup in new thread here
    Waiter.return_when_done()  
  
And then when the popup closes:

    Waiter.wait = False
   
# let thread die

That should work? but maybe do a small test demo before going the whole hog...:-)

Peace out

ZenCODE

unread,
Jul 3, 2014, 4:16:27 PM7/3/14
to kivy-...@googlegroups.com
To extend that to multiple blockers, something like this? Manage a queue where each block in unblocked in sequence (not tested, but seems logical?)

class Waiter(object):
    waiters
= []

   
@staticmethod
   
def return_when_done(obj):
       
""" obj needs to be unique to each call """
       
Waiter.waiters.append(obj)
       
while obj in Waiter.waiters:
            sleep
(0.25)
 
     
@staticmethod
     
def done():
         
Waiter.waiters.pop()
 



tsmoore

unread,
Jul 3, 2014, 5:05:52 PM7/3/14
to kivy-...@googlegroups.com
Thanks for the suggestion. I'll try that next week and I'll pass on my results. I appreciate the idea. 

Tysen Moore

unread,
Jul 7, 2014, 10:57:08 AM7/7/14
to kivy-...@googlegroups.com
I played a bit with your suggestions and the concept works.  I wrote a simple test [below] and it seems to work.  I did not test the "multi-blocker" solution but I think it would extend just fine.  Hopefully I am not making some other mistakes, but it seems to work for the simple case.  This also avoid a major tear up of my existing code.

Thanks for the help.

import sys
import time
import threading

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty

from kivy.lang import Builder
from kivy.uix.popup import Popup

Builder.load_string('''
<TestView>:
    okBtn:          idOK
    orientation:    "vertical"

    Label:
        text:       "Testing Blocking View"
   
    Button:
        id:         idOK
        text:       "OK"

'''
)

class TestView(BoxLayout):

    blocking
= BooleanProperty(False)
    popup    
= None

   
def __init__(self, **kwargs):
       
super(TestView, self).__init__(**kwargs)
       
self.okBtn.bind( on_release=self.OnPress )

   
def open (self):
       
self.popup = Popup(title           = "Testing...",
                           content        
= self,
                           size_hint      
= (None, None),
                           size            
= (250,150),
                           auto_dismiss    
= False )
       
self.popup.open()
       
       
if self.blocking:
           
if threading.current_thread().name != "MainThread":
               
# NOT executing on the main thread so allow blocking
               
while(self.blocking):
                    time
.sleep(0.25)
               
self.popup.dismiss()
       
   
def OnPress (self, *args):
       
print "PRESSED:", args[0].text

       
if self.blocking == False:
           
self.popup.dismiss()
       
self.blocking = False

       


class TestApp(App):

   
def build(self):
        root
= BoxLayout(orientation='vertical')

       
self.startParsing()
       
return root

   
def parse (self, *args):

       
print "Parsing", args[0]
        time
.sleep(2.0)

       
print "Open View..."
        view
= TestView( blocking=True )
        view
.open()

       
print "***** AFTER OPEN EXECUTED *****"

   
def startParsing (self):

        t
= threading.Thread( target=self.parse, args = ["/tmp/file"] )
        t
.start()

TestApp().run()



Tysen Moore

unread,
Jul 7, 2014, 1:53:33 PM7/7/14
to kivy-...@googlegroups.com
After testing the code and changing the model to a Semaphore I have a more fundamental question, HOW does this work?  I guess I don't really understand the Kivy event model.  If the popup is started from the other "parsing" thread, how does the popup still get the touch events, etc?  My previous code snippet does function as I'd expect, I would really like to understand how.  Thanks.

ZenCODE

unread,
Jul 7, 2014, 4:13:29 PM7/7/14
to kivy-...@googlegroups.com
Many questions, so little time...;-) Kivy is a little bit different in that it works with OpenGL. It therefore tries to free the GPU using the Observer pattern. But blah blah. Essentially, the Python GIL (https://wiki.python.org/moin/GlobalInterpreterLock) means you can think of "sleep" as a "let other stuff be done" call.

http://www.tutorialspoint.com/python/python_multithreading.htm

So, I'm happy to try and explain how this works (to the best of my limited understanding), but can you be more specific about your questions? :-)


tsmoore

unread,
Jul 7, 2014, 6:39:17 PM7/7/14
to kivy-...@googlegroups.com
Sorry I should have been more explicate. I understand threading. The question is that the main thread is running the main kivy loop (touch events, drawing, etc). Now I start a new loop to parse. This new loop then opens a pop up and blocks. How does kivy still get events to the popup thread--which is blocked?  Or does the popup actually still run in the main thread, thus the reason it works.  I suspect the main thread still does the drawing and events for the popup even though it was started on the different thread. Is this correct?

ZenCODE

unread,
Jul 8, 2014, 1:57:30 AM7/8/14
to kivy-...@googlegroups.com
"I suspect the main thread still does the drawing and events for the popup even though it was started on the different thread. Is this correct?"

Basically (as I understand it), all rendering is done when your code is not executing. The OpenGL graphics instructions are actually sitting on the GPU, not the CPU where your code is. All we do is change these graphics instructions and they rendered after our code exits.

So it's not too important which thread alters these things. The important thing is to provide idle time so Kivy can handle the updating/scheduling etc. That's why the Clock is so useful in Kivy. It allows you to schedule operations for execution after the rendering and layout has been done.

Hope that helps?

Tysen Moore

unread,
Jul 8, 2014, 6:52:11 AM7/8/14
to kivy-...@googlegroups.com
Thanks so much for the background.  This provides a clearer picture.

Philippe Faure

unread,
Apr 21, 2017, 11:16:33 PM4/21/17
to Kivy users support, tsmoo...@gmail.com
Hello,
I had a look at your code, as I am trying to find a way to get a blocking Popup message using Kivy.  Your code runs up till the "open view" message, then I get a segmentation fault with no other errors or information.  I was wondering if someone had seen this in the past, and what might be causing it.

Thank you

ZenCODE

unread,
Apr 22, 2017, 3:10:38 PM4/22/17
to Kivy users support, tsmoo...@gmail.com
@Philippe Faure

This is a very old post, and your needs will be confused by it's history. Please make a new post clearly stating your problems, and preferably with runnable code demonstrating the issue.

Philippe Faure

unread,
Apr 23, 2017, 9:02:45 AM4/23/17
to Kivy users support, tsmoo...@gmail.com
Hello ZenCode,
Thank you for your suggestion.  After I posted this, I went tried the original code again, and found that I had a formatting error.  It works, thank you.
Reply all
Reply to author
Forward
0 new messages