Kivy Popup 在循环结束时显示
Kivy Popup displays at the end of cycle
我有一个处理数据的脚本 - 例如 5 个 csv 文件。脚本加载 csv 后,它会要求用户使用 Popup window 为特定的 csv 提供额外的数据输入,因此在这种情况下,将有 5 个 Popup windows.
问题是脚本忽略了代码所需部分的 Popup windows 调用,并在代码的最后显示它们。它以相反的顺序显示它,但是也就是说,因为最新的 window 在旧的之上。
下面是一段代码,代表了我的问题。在评论部分,有我的第一次尝试,在主线程中简单地调用了 Popup。已经有人问过类似的问题,所以我用线程修改了代码,但是它没有解决问题,因为已经问过的问题是进度条,应该 运行 代码与我假设的弹出窗口。
所以我的问题是:有没有办法在调用 Popup 时以及用户在 Popup 中提供变量后冻结代码然后 使用来自用户的变量继续代码。
test.kv :
<FirstWindow>
name: "second"
canvas.before:
Color:
rgba: (0.91,0.91,0.91,1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.2
size_hint_x: 1
BoxLayout:
orientation: "horizontal"
spacing:10
Button:
font_size: 30
text: "Press to get Popup"
on_release:
root.manager.transition.direction = "left"
root.Main_code()
Label:
size_hint_y: 0.2
size_hint_x: 1
<MyPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Test'
BoxLayout:
text_input: text_input
text_input2: text_input2
orientation: 'vertical'
Label:
id: Datum
font_size: 25
BoxLayout:
Label:
text: "Test line one"
TextInput:
id: text_input
BoxLayout:
Label:
text: "Test line two"
TextInput:
id: text_input2
Button:
text: 'Confirm'
on_press: root.dismiss()
.py 文件:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.properties import StringProperty
import threading
Window.size = (1200, 700)
class FirstWindow(Screen):
popup_text = StringProperty()
popup_text2 = StringProperty()
def poptest (self,date):
p = MyPopup(date)
p.content.text_input.bind(text=self.setter('popup_text'))
p.content.text_input2.bind(text=self.setter('popup_text2'))
p.open()
def Main_code(self):
year = " .1.2020 0:00"
con = 1
while con<5:
date = str(con) + year
mythread = threading.Thread(target=self.poptest(date))
mythread.start()
# p = MyPopup(date)
# p.content.text_input.bind(text=self.setter('popup_text'))
# p.content.text_input2.bind(text=self.setter('popup_text2'))
# p.open()
print(self.popup_text)
print(self.popup_text2)
print("Cycle " + str(con) + " finished")
con +=1
class MyPopup(Popup):
date = StringProperty()
def __init__(self, date, **kwargs):
super(MyPopup, self).__init__(**kwargs)
self.ids.Datum.text = "Date since: " + str(date)
class WindowManager(ScreenManager):
pass
with open("test.kv", encoding='utf-8') as f:
Builder.load_string(f.read())
window = WindowManager()
screens = [FirstWindow(name="second")]
for screen in screens:
window.add_widget(screen)
window.current = "second"
class MyMainApp(App):
def build(self):
return window
if __name__ == "__main__":
MyMainApp().run()
非常感谢任何帮助。
您可以使用locks 强制一个线程等待另一个线程。这是使用锁的代码的修改版本:
from functools import partial
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.properties import StringProperty
import threading
Window.size = (1200, 700)
class FirstWindow(Screen):
popup_text = StringProperty()
popup_text2 = StringProperty()
def poptest (self, p, dt):
# the instance of MyPopup is passed as an arg
p.content.text_input.bind(text=self.setter('popup_text'))
p.content.text_input2.bind(text=self.setter('popup_text2'))
p.open()
def Main_code(self):
# run the loop in another thread (not the main thread)
mythread = threading.Thread(target=self.old_main_code, daemon=True)
mythread.start()
def old_main_code(self):
# create a lock to be used in keeping this thread and the MyPopups sychronized
lock = threading.Lock()
lock.acquire()
year = " .1.2020 0:00"
con = 1
while con<5:
date = str(con) + year
lock.release() # release the lock so that the MyPopup can acquire it
pop = MyPopup(lock, date) # create Popup here to be sure it acquires lock
Clock.schedule_once(partial(self.poptest, pop)) # run poptest on main thread
lock.acquire() # wait for the Popup to release the lock
print(self.popup_text)
print(self.popup_text2)
print("Cycle " + str(con) + " finished")
con +=1
class MyPopup(Popup):
date = StringProperty()
def __init__(self, lock, date, **kwargs):
lock.acquire() # acquire the lock to force the other thread to wait
super(MyPopup, self).__init__(**kwargs)
self.ids.Datum.text = "Date since: " + str(date)
self.lock = lock
def myDismiss(self):
self.dismiss()
self.lock.release() # release the lock to allow while loop to continue
class WindowManager(ScreenManager):
pass
with open("test.kv", encoding='utf-8') as f:
Builder.load_string(f.read())
window = WindowManager()
screens = [FirstWindow(name="second")]
for screen in screens:
window.add_widget(screen)
window.current = "second"
class MyMainApp(App):
def build(self):
return window
if __name__ == "__main__":
MyMainApp().run()
对 kv
文件的唯一更改是将 Confirm
按钮设置为调用 root.myDismiss()
:
Button:
text: 'Confirm'
on_press: root.myDismiss()
我有一个处理数据的脚本 - 例如 5 个 csv 文件。脚本加载 csv 后,它会要求用户使用 Popup window 为特定的 csv 提供额外的数据输入,因此在这种情况下,将有 5 个 Popup windows.
问题是脚本忽略了代码所需部分的 Popup windows 调用,并在代码的最后显示它们。它以相反的顺序显示它,但是也就是说,因为最新的 window 在旧的之上。
下面是一段代码,代表了我的问题。在评论部分,有我的第一次尝试,在主线程中简单地调用了 Popup。已经有人问过类似的问题,所以我用线程修改了代码,但是它没有解决问题,因为已经问过的问题是进度条,应该 运行 代码与我假设的弹出窗口。
所以我的问题是:有没有办法在调用 Popup 时以及用户在 Popup 中提供变量后冻结代码然后 使用来自用户的变量继续代码。
test.kv :
<FirstWindow>
name: "second"
canvas.before:
Color:
rgba: (0.91,0.91,0.91,1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.2
size_hint_x: 1
BoxLayout:
orientation: "horizontal"
spacing:10
Button:
font_size: 30
text: "Press to get Popup"
on_release:
root.manager.transition.direction = "left"
root.Main_code()
Label:
size_hint_y: 0.2
size_hint_x: 1
<MyPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Test'
BoxLayout:
text_input: text_input
text_input2: text_input2
orientation: 'vertical'
Label:
id: Datum
font_size: 25
BoxLayout:
Label:
text: "Test line one"
TextInput:
id: text_input
BoxLayout:
Label:
text: "Test line two"
TextInput:
id: text_input2
Button:
text: 'Confirm'
on_press: root.dismiss()
.py 文件:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.properties import StringProperty
import threading
Window.size = (1200, 700)
class FirstWindow(Screen):
popup_text = StringProperty()
popup_text2 = StringProperty()
def poptest (self,date):
p = MyPopup(date)
p.content.text_input.bind(text=self.setter('popup_text'))
p.content.text_input2.bind(text=self.setter('popup_text2'))
p.open()
def Main_code(self):
year = " .1.2020 0:00"
con = 1
while con<5:
date = str(con) + year
mythread = threading.Thread(target=self.poptest(date))
mythread.start()
# p = MyPopup(date)
# p.content.text_input.bind(text=self.setter('popup_text'))
# p.content.text_input2.bind(text=self.setter('popup_text2'))
# p.open()
print(self.popup_text)
print(self.popup_text2)
print("Cycle " + str(con) + " finished")
con +=1
class MyPopup(Popup):
date = StringProperty()
def __init__(self, date, **kwargs):
super(MyPopup, self).__init__(**kwargs)
self.ids.Datum.text = "Date since: " + str(date)
class WindowManager(ScreenManager):
pass
with open("test.kv", encoding='utf-8') as f:
Builder.load_string(f.read())
window = WindowManager()
screens = [FirstWindow(name="second")]
for screen in screens:
window.add_widget(screen)
window.current = "second"
class MyMainApp(App):
def build(self):
return window
if __name__ == "__main__":
MyMainApp().run()
非常感谢任何帮助。
您可以使用locks 强制一个线程等待另一个线程。这是使用锁的代码的修改版本:
from functools import partial
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.properties import StringProperty
import threading
Window.size = (1200, 700)
class FirstWindow(Screen):
popup_text = StringProperty()
popup_text2 = StringProperty()
def poptest (self, p, dt):
# the instance of MyPopup is passed as an arg
p.content.text_input.bind(text=self.setter('popup_text'))
p.content.text_input2.bind(text=self.setter('popup_text2'))
p.open()
def Main_code(self):
# run the loop in another thread (not the main thread)
mythread = threading.Thread(target=self.old_main_code, daemon=True)
mythread.start()
def old_main_code(self):
# create a lock to be used in keeping this thread and the MyPopups sychronized
lock = threading.Lock()
lock.acquire()
year = " .1.2020 0:00"
con = 1
while con<5:
date = str(con) + year
lock.release() # release the lock so that the MyPopup can acquire it
pop = MyPopup(lock, date) # create Popup here to be sure it acquires lock
Clock.schedule_once(partial(self.poptest, pop)) # run poptest on main thread
lock.acquire() # wait for the Popup to release the lock
print(self.popup_text)
print(self.popup_text2)
print("Cycle " + str(con) + " finished")
con +=1
class MyPopup(Popup):
date = StringProperty()
def __init__(self, lock, date, **kwargs):
lock.acquire() # acquire the lock to force the other thread to wait
super(MyPopup, self).__init__(**kwargs)
self.ids.Datum.text = "Date since: " + str(date)
self.lock = lock
def myDismiss(self):
self.dismiss()
self.lock.release() # release the lock to allow while loop to continue
class WindowManager(ScreenManager):
pass
with open("test.kv", encoding='utf-8') as f:
Builder.load_string(f.read())
window = WindowManager()
screens = [FirstWindow(name="second")]
for screen in screens:
window.add_widget(screen)
window.current = "second"
class MyMainApp(App):
def build(self):
return window
if __name__ == "__main__":
MyMainApp().run()
对 kv
文件的唯一更改是将 Confirm
按钮设置为调用 root.myDismiss()
:
Button:
text: 'Confirm'
on_press: root.myDismiss()