Pause a python script until an event occurs without hanging/blocking the GUI

妖精的绣舞 提交于 2021-02-18 12:48:06

问题


Trying to migrate from PyQt with Kivy and I cant even imagine a solution for this.

I have thousands of lines of code that use Qt's dialogues for text input. That is, when their line of code is reached, they 'stop' the script until the "ok" button is pressed, so they can return the text input.

Kivy doesnt have that functionality, so ideally, when the program needs user input, the "ok" button would call for the next function to run.

Therefore I must replace all the current calls to a PyQt function with a function that stops the running script, launches a working responsive dialogue, then resumes the original when it has the text input it requested. So the question is:

Is there a way to stop a running script until a function finishes, without hanging the GUI?

I have already tried:

  • Threading:

Even if I start the text input in a new thread:

t = threading.Thread(target=TextInput.waiter)

the function that calls such thread will return just after calling the text input. If I use this code:

t.start()
t.join()

The main script will stop, but also hangs the text input GUI.

  • While/Sleep: Waiting for the text input variable to contain a valid result. But this blocks the ongoing textinput GUI in Kivy

  • Hacking raw_input: Currently thinking into try some hack with that, that would allow me to stop the script, then feed back the input found by the kivy text input popup.

Any pointers would be really welcome, thanks for reading.


回答1:


You can't just pause the running script. Instead, you'll need to refactor your program to be event-driven (as Kivy is an event-driven GUI).

Here's a simple example function:

def myfunc():
    # do some stuff here
    # now we need some input...
    val = qt_input_dialogue()
    # do some more stuff here

Refactored:

class MyPopup(Popup):
    value = StringProperty() # bind this to a TextInput or something

def myfunc1():
    # do some stuff here
    p = MyPopupClass()
    p.bind(on_dismiss=lambda *_: myfunc2(p.value))
    p.open()

def myfunc2(val):
    # do some more stuff here

If you're willing to use Twisted, you can make this even easier using Deferreds and inlineCallbacks.

from kivy.support import install_twisted_reactor
install_twisted_reactor()

from twisted.internet import defer

Builder.load_string('''
<MyPopup>:
    BoxLayout:
        orientation: 'vertical'
        TextInput:
            id: text_input
        BoxLayout:
            orientation: 'horizontal'
            Button:
                text: 'OK'
                on_press: root.okfn(text_input.text)
''')

class MyPopup(Popup):
    def show(self, *args):
        d = defer.Deferred()
        self.okfn = d.callback
        self.open(*args)
        return d

@defer.inlineCallbacks
def myfunc():
    # do some stuff here
    val = yield MyPopup().show()
    # do some more stuff here

This way, you can just replace the calls to QT input dialogues with yield MyPopup().show().



来源:https://stackoverflow.com/questions/23685986/pause-a-python-script-until-an-event-occurs-without-hanging-blocking-the-gui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!