2014-02-19 111 views
0

我想創建一個函數,只有在用戶將文本輸入到TextInput中並單擊確定按鈕時纔會返回其值。例如使用Kivy創建輸入對話框

n = PopupInput("What number should I add?") 
print 5+n 

我想不出如何編寫一個kivy對話框,它將暫停執行,並等待用戶關閉它。在其他GUI工具包,我會用類似

while True: 
    if dialog.visable == False: 
     return int(textbox.text) 
    else: 
     wx.Yield() 

爲了讓我的代碼只是坐在一個地方同時允許GUI框架,做它的事。但是,我發現基維沒有同等的方法。

編輯:

這裏是我的失敗嘗試(它的雜亂)

def PopupOk(text, title='', btn_text='Continue'): 
    btnclose = Button(text=btn_text, size_hint_y=None, height='50sp') 
    content = BoxLayout(orientation='vertical') 
    p = Popup(title=title, content=content, size=('300dp', '300dp'), 
       size_hint=(None, None)) 
    content.add_widget(Label(text=text)) 
    ti = TextInput(height='50sp', font_size='50sp', input_type='number') 
    content.add_widget(ti) 
    def _on_d(*args): 
     p.is_visable = False 
    p.bind(on_dismiss=_on_d) 
    p.is_visable = True 

    content.add_widget(btnclose) 

    btnclose.bind(on_release=p.dismiss) 
    p.open() 
    while not p.is_visable: 
     EventLoop.idle() 
    return ti.text 

回答

3

,我覺得這個倒過來 - 你真的想要做的是打印時彈出數關閉了。

假設您有一個帶有textinput的彈出窗口供用戶輸入,您可以在彈出窗口關閉時執行popup.bind(on_dismiss=some_function)以運行some_function。這意味着你所需要做的就是編寫一個函數,它會彈出一個窗口,檢索文本框文本,並打印出你想要的任何答案。

我不確定這是如何直接適合您真正想要做的事情,但這是與Kivy的事件系統一起工作的更自然的方式。如果你有一些非常不同的要求,我可以以不同的方式回答。

編輯:看到您的編輯,這幾乎就是您所做的,但我認爲嘗試以這種方式擊敗事件回覆而不是按照流程進行提交是一個壞主意。我會創建一個新的函數(正如我上面所說的),它接受一個文本輸入並執行任何你想要的。通過將on_dismiss綁定到此函數,您可以讓kivy在稍後用戶開始解散彈出窗口時開始計算。

+0

Thanks @inclement。我已經閱讀了一些遵循該範式的示例,但它不適合我,因爲發生了什麼是用戶按下了一個按鈕 - 調用了一個函數 - 並且完成了一些計算,然後顯示提示符回到我在那個功能中停止的地方。爲了讀者的緣故,我寧願不必將這個功能分成兩半。 – jsexauer

+0

我想過了,但我沒有比我建議的更好的想法,這對我來說似乎很自然。說實話,我不相信這種範式對你來說是錯誤的,但這是你的選擇,我當然不能聲稱它是一個權威。 – inclement

+1

對我來說這似乎很奇怪,這是無法完成的。在其他GUI框架中,它是非常標準的,它具有簡單的對話框並調用一個函數來獲取用戶對提示的響應。只是感到驚訝,沒有乾淨的方式在基維做。感謝您的幫助,一如既往。 (順便說一句,謝謝你回答如此多的Kivy問題;我發現它們是非常寶貴的) – jsexauer

1

Kivy的確建立在事件和異步回調的原則基礎上。因爲它使用OpenGL並依賴GPU上呈現的幀而不是CPU,所以您永遠不想使用阻止代碼。所以kivy使用事件綁定來規避問題。

以下是一種方法。

from kivy.app import App 
from kivy.uix.popup import Popup 
from kivy.uix.button import Button 
from kivy.uix.textinput import TextInput 


class MainApp(App): 
    def build(self): 
     self.button = Button(text="Click", 
          on_release=self.get_caption) 
     return self.button 

    def get_caption(self, btn): 
     Popup(title="Enter text here", 
       content=TextInput(focus=True), 
       size_hint=(0.6, 0.6), 
       on_dismiss=self.set_caption).open() 

    def set_caption(self, popup): 
     self.button.text = popup.content.text 

MainApp().run() 

將內容放置在彈出窗口中,當給它一個「set_caption」函數以便在被解僱時調用。你在那裏迴應變化。沒有阻塞。沒有等待。已經與線程的工作停止的GUI wxWidgets的阻擋,我真的認爲這是一個更好的辦法... ;-)

乾杯

1

你在找什麼可以用下面的代碼來實現。您需要在主程序中指定例程作爲方法:

import kivy 
kivy.require('1.5.0') # replace with your current kivy version ! 
from kivy.uix.popup import Popup 
from kivy.uix.button import Button 
from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.label import Label 
from kivy.app import App 
from kivy.clock import Clock 

class YourApp(App): 

    def build(self): 
     return Button(text='Press for popup!', on_press=self.callpopup) 

    def callpopup(self, event): 
     dlg = MessageBox(titleheader="Titel Header", message="Any Message", options={"YES": "printyes()", "NO": "printno()"}) 
     print "Messagebox shows as kivy popup and we wait for the \nuser action and callback to go to either routine" 

    def printyes(self): 
     # routine for going yes 
     print "You chose the Yes routine" 

    def printno(self): 
     # routine for going no 
     print "You chose the No routine" 

class MessageBox(YourApp): 
    def __init__(self, titleheader="Title", message="Message", options={"OK": "self.ok()", "NO": "self.no()"}): 

     def popup_callback(instance): 
      "callback for button press" 
      # print('Popup returns:', instance.text) 
      self.retvalue = instance.text 
      self.popup.dismiss() 

     self.retvalue = None 
     self.options = options 
     box = BoxLayout(orientation='vertical') 
     box.add_widget(Label(text=message, font_size=20)) 
     b_list = [] 
     buttonbox = BoxLayout(orientation='horizontal') 
     for b in options: 
      b_list.append(Button(text=b, size_hint=(1,.35), font_size=20)) 
      b_list[-1].bind(on_press=popup_callback) 
      buttonbox.add_widget(b_list[-1]) 
     box.add_widget(buttonbox) 
     self.popup = Popup(title=titleheader, content=box, size_hint=(None, None), size=(400, 400)) 
     self.popup.open() 
     self.popup.bind(on_dismiss=self.OnClose) 

    def OnClose(self, event): 
     self.popup.unbind(on_dismiss=self.OnClose) 
     self.popup.dismiss() 
     if self.retvalue != None: 
      command = "super(MessageBox, self)."+self.options[self.retvalue] 
      # print "command", command 
      exec command 

if __name__ == '__main__': 
    YourApp().run()