Meine Kivy App hat eine Taste, deren Rückruf eine UrlRequest
beinhaltet. Ich möchte ein Popup bereitstellen, das den Benutzer auffordert, zu warten, während die Anfrage abgeschlossen wird. Das Problem besteht darin, dass das Ausführen der Anforderung selbst das Popup blockiert. Ich habe versucht, die open()
Methode des Popup an verschiedenen Orten ohne Glück zu platzieren. Im folgende Beispiel wird das Popup im on_progress()
Rückruf der UrlRequest
geöffnet:Kivy: Popup ist vom Haupt-Thread blockiert
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.garden.navigationdrawer import NavigationDrawer
from kivy.network.urlrequest import UrlRequest
from kivy.uix.popup import Popup
from kivy.uix.label import Label
import urllib
kv = '''
<[email protected]>:
canvas:
Color:
rgb: (0.09,0.65,0.8)
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint: .3, .2
pos_hint: {'center_x': .5,'center_y': .25}
text: 'Call Request'
# on_press: app.p.open()
on_release: app.callback1()
Label:
text: 'This is ' + root.name
font_size: '50sp'
<MyNavDrawer>:
BoxLayout:
orientation: 'vertical'
size_hint_y: .25
pos_hint: {'center_y':.5}
Button:
text: 'Screen 1'
on_press: app.callback2('screen1')
Button:
text: 'Screen 2'
on_press: app.callback2('screen2')
SMRoot:
<SMRoot>:
ScreenTemplate:
name: 'screen1'
ScreenTemplate:
name: 'screen2'
'''
Builder.load_string(kv)
class SMRoot(ScreenManager):
pass
class SignUpScreen(Screen):
pass
class myNavDrawer(NavigationDrawer):
pass
class myApp(App):
popup_opened = False
p=Popup(title="Posting request...",
content=Label(text="... Please wait"),
size=(100, 100),
size_hint=(0.5, 0.5),
auto_dismiss = False)
def build(self):
self.mynavdrawer = myNavDrawer()
return self.mynavdrawer
def on_success(self, req, results):
print 'In on_success: '+ results
self.p.title = 'Success'
self.p.content = Label(text=results)
self.p.auto_dismiss = True
popup_opened = False
def on_failure(self, req, results):
self.p.title = 'Failure'
self.p.content = Label(text=results)
print 'In on_failure: '+ results
self.p.auto_dismiss = True
def on_error(self, req, results):
self.p.title = 'Error'
self.p.content = Label(text=results.strerror)
print 'In on_error: '+ results.strerror
self.p.auto_dismiss = True
def on_progress (self, req, results, chunk):
if not self.popup_opened:
print 'In on_progress: '+ str(results)
self.p.open()
self.popup_opened = True
def callback1(self):
params={'show_env':'1'}
params = urllib.urlencode(params)
headers = {'Content-type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
url = 'https://httpbin.org/get'
req = UrlRequest(url,
self.on_success,
req_body = params,
req_headers = headers,
on_failure=self.on_failure,
on_error=self.on_error,
on_progress=self.on_progress,
timeout=4)
req.wait()
print 'After UrlRequest'
if __name__ == '__main__':
myApp().run()
Lauf dies bewirkt, dass das Popup nach erscheint die Anforderung abgeschlossen ist, die den Zweck besiegt.
Beachten Sie die kommentierte on_press: app.p.open()
Bindung in der Schaltfläche unter <[email protected]>
. Dies funktioniert perfekt, außer dass es eine Workaround ist, die alles andere als ideal ist. Ich möchte, dass das Popup geöffnet wird, wenn die UrlRequest
gesendet wird; Die obige Problemumgehung muss auf jede Schaltfläche angewendet werden.
Irgendwelche Ideen, wie man den Knopf vom Hauptfaden öffnet, während der Rückruf ausgeführt wird, würde geschätzt werden. Ich habe versucht, auch Clock.schedule_once()
zu verwenden. Von der docs scheint es EventDispatcher.dispatch()
könnte den Trick, aber ich weiß nicht, welches Ereignis zu versenden.
Die 'wait()' in der Tat blockiert den Thread. Ich migriere jedoch vorhandenen Code aus der synchronen Anforderungsbibliothek in das asynchrone UrlRequest. Ich hoffte, dass ich in der Zwischenzeit das 'wait()' benutzen konnte, um die Dinge nicht zu unterbrechen. Ich denke, das ist aufgrund [dieses bekannte Problem] (https://groups.google.com/forum/#!topic/kivy-users/ERcZDjr3znE) einfach nicht möglich. – ScissorHill
@ScissorHill - Ich habe meine Antwort aktualisiert, so dass Sie Ihr altes Verhalten replizieren können ... –