Kivy - 弹出窗口 A 显示在弹出窗口 B 之上
Kivy - popup A shows over popup B
问题
我有一个循环,在每个段落中都显示一个弹出窗口。我将其称为 popup_A。在循环中有一个条件,当满足时它会同时触发另一个弹出窗口和线程中的一个方法。我将第二个弹出窗口称为 popup_B。问题是它确实显示了 popup_B,但紧接着 popup_A 显示在 [=108= 之上,完全覆盖了它。为了更好地了解流程:
def myFun:
if condition1:
method1
if condition2:
method2
if condition3:
show popup_B
thread method3
thread popup_A
def popup_A:
do something
display message_A
call myFun
def popup_B:
display message_B
代码
循环涉及的方法:
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data["tasks"]): # check the counter
self.code = self.data["tasks"][self.counter].get("code")
action = self.data["tasks"][self.counter].get("actionDescription")
if "myCondition" in str(action):
#set the popup structure
self.popup_B = ActivityBox(self)
self.popup_B.open()
# run the method in a thread
t1 = threading.Thread(target = timeConsumingMethod)
t1.start()
# dismiss the popup ActivityBox
self.popup_B.dismiss()
# call popup_A in thread
t3 = threading.Thread(target = self.popup_A)
t3.start()
def do(self):
self.counter = self.counter + 1
self.popup.dismiss()
self.goForward()
def cancel(self):
self.counter = self.counter + 1
self.popup.dismiss()
self.goForward()
def popup_A(self):
self.popup = MessageBox(self)
self.popup.open()
Builder.load_string()
中的 ActivityBox 和 MessageBox 弹出结构:
<MessageBox>:
size_hint: 1, .7
auto_dismiss: False
title: "MessageBoxTitle"
title_align: "center"
title_size: 30
BoxLayout:
orientation: "vertical"
Label:
font_size: '30sp'
text: "MessageBoxLabel"
BoxLayout:
orientation: "horizontal"
spacing: 10
size_hint: 1, .5
Button:
font_size: 50
background_color: 0,204,0,1
text: "CONFIRM"
on_press:
self.disabled = True
self.background_color = 0,255,0,1
app.do()
root.dismiss()
Button:
font_size: 50
background_color: 204,0,0,1
text: "CANCEL"
on_press:
self.background_color = 255,0,0,1
app.cancel()
root.dismiss()
<ActivityBox>:
size_hint: 1, .7
auto_dismiss: False
title: "ActivityBoxTitle"
title_align: "center"
title_size: 30
BoxLayout:
orientation: "vertical"
Label:
font_size: '30sp'
text: "ActivityBoxLabel"
BoxLayout:
orientation: "horizontal"
spacing: 10
size_hint: 1, .5
代码说明
主循环的组件是 goForward
和 popup_A。随着循环的每一段, popup_A 出现,在线程中调用。然后 popup_A 回调 goForward
。如果满足 goForward
中的条件“工作”,则显示“进行中的工作”popup_B。 popup_B 运行 与线程中的方法一起使用,否则 Kivy 不会显示弹出窗口(锁定 GUI)。
结果
到目前为止我已经尝试过:
- 运行 popup_B in a thread
t1 = threading.Thread(target = self.popup.open)
: popup_A 覆盖 popup_B.
- 使用线程
.join()
:popup_A出现但popup_B不出现,.join()忽略它。
- 运行 popup_B 和
timeConsumingMethod
一起在一个线程中: popup_A 出现但 popup_B 没有出现。
- 运行
timeConsumingMethod
作为进程:popup_A 出现但 popup_B 不出现,程序挂起。
- 使用
mutex = threading.Lock()
锁定带有 popup_B 的线程:popup_A 出现在 popup_B 之上。 GUI 也会出现乱码。
- 运行 popup_A 不在一个线程中 运行 popup_B 和
timeConsumingMethod
一起在一个线程中: popup_A 出现popup_B.
问题
popup_A 只有在线程中的方法完成并且 popup_B 被关闭后才能显示。如何防止 popup_A 覆盖 popup_B?
我查看了下面的帖子,但没有找到解决方案。
--- 更新 20200715 -------------------------------- --------------
在代码中,我在 popup_B 中将弹出窗口重命名为“进行中”,在 popup_A[=87 中重命名弹出窗口 2 =] 以便更好地理解。
--- 更新 20200716 -------------------------------- --------------
我使用 Clock.schedule_once
修改了代码 step2
(线程 popup_A
和 step3
(线程 timeConsumingMethod
和 popup_B
). popup_B
上升但 popup_A
覆盖它直到最后一个 popup_A
被按钮关闭。等待 timeConsumingMethod
在没有 [=26= 的情况下完成] 启动,我使用 while loop
。代码如下:
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data["tasks"]): # check the counter
self.code = self.data["tasks"][self.counter].get("code")
action = self.data["tasks"][self.counter].get("actionDescription")
if "myCondition" in str(action):
self.returnStatus = 1 # set status
#the two rows below give the same result
#self.popup_B = ActivityBox(self)
#self.popup_B.open()
Clock.schedule_once(self.step3)
# run the method in a thread
t1 = threading.Thread(target = self.step1)
t1.start()
while self.returnStatus != 0:
time.sleep(1)
Cloch.schedule_once(self.step2)
def step1(self):
ts1 = threading.Thread(target = self.timeConsumingMethod)
ts1.start()
ts1.join()
self.returnStatus = 0 # change status when over
return(self.returnStatus)
def step2(self, *args):
ts2 = threading.Thread(target = self.popup_A)
ts2.start()
def step3(self, *args):
#set the popup structure
self.popup = ActivityBox(self)
self.popup.open()
def popup_A(self):
self.popup = MessageBox(self)
t3 = threading.Thread(target = self.popup.open)
t3.start()
def do(self):
self.counter = self.counter + 1
self.popup.dismiss()
self.goForward()
def cancel(self):
self.counter = self.counter + 1
self.popup.dismiss()
exit()
- Correct way to implement loading popup in kivy app
让 popup_A 在耗时线程完成之前不弹出的一种方法是在耗时线程结束时调用 popup_A。尝试将 goForward()
方法分成两部分。第一部分几乎没有变化:
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data["tasks"]): # check the counter
self.code = self.data["tasks"][self.counter].get("code")
action = self.data["tasks"][self.counter].get("actionDescription")
if "myCondition" in str(action):
#set the popup structure
self.popup_B = ActivityBox(self)
self.popup_B.open()
# run method in a thread
t1 = threading.Thread(target = self.timeConsumingMethod)
t1.start()
我已将 timeConsumingMethod()
移至 class,因此需要在 Thread
中调用 self.timeConsumingMethod
。
然后将其余的旧goForward()
方法放在一个单独的方法中(我称之为step2()
):
def step2(self, *args):
# dismiss the popup ActivityBox
self.popup_B.dismiss()
# call popup_A in thread
t3 = threading.Thread(target=self.popup_A)
t3.start()
然后在timeConsumingMethod()
中,完成后调用step2()
:
def timeConsumingMethod(self):
time.sleep(5)
Clock.schedule_once(self.step2)
解决方案
我已经使用线程解决了弹出窗口重叠的问题。我想问题出在共享内存和解释器锁上。
代码
我修改了代码并将 threading.Thread
添加到绑定到弹出窗口按钮的方法 do(self)
和 cancel(self)
中。 step1
在线程中运行 timeConsumingMethod
,step2
调用在线程中运行的 popup_A,step3
在线程中运行 popup_B一个线程。这样 popup_A 确实显示并在 popup_B 出现时被解雇。
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data): # check the counter
if "myCondition":
self.step3()
self.step1()
self.popup_A()
def step1(self):
self.popup_A.dismiss() # dismiss the popup A first
ts1 = threading.Thread(target = self.timeConsumingMethod)
ts1.start()
ts1.join()
self.popup_B.dismiss() # dismiss the popup B at the end
def step2(self, *args):
self.popup_A()
def step3(self, *args):
#set the popup structure
self.popup_B = ActivityBox(self)
ts3 = threading.Thread(target = self.popup_B.open)
ts3.start()
ts3.join()
def popup_A(self):
self.popup_A = MessageBox(self)
t3 = threading.Thread(target = self.popup_A.open)
t3.start()
def do(self):
self.counter = self.counter + 1
self.popup_A.dismiss() # dismiss the popup A first
td = threading.Thread(target = self.goForward)
td.start()
def cancel(self):
self.counter = self.counter + 1
self.popup_A.dismiss() # dismiss the popup A first
tc = threading.Thread(target = self.goForward)
tc.start()
问题
我有一个循环,在每个段落中都显示一个弹出窗口。我将其称为 popup_A。在循环中有一个条件,当满足时它会同时触发另一个弹出窗口和线程中的一个方法。我将第二个弹出窗口称为 popup_B。问题是它确实显示了 popup_B,但紧接着 popup_A 显示在 [=108= 之上,完全覆盖了它。为了更好地了解流程:
def myFun:
if condition1:
method1
if condition2:
method2
if condition3:
show popup_B
thread method3
thread popup_A
def popup_A:
do something
display message_A
call myFun
def popup_B:
display message_B
代码 循环涉及的方法:
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data["tasks"]): # check the counter
self.code = self.data["tasks"][self.counter].get("code")
action = self.data["tasks"][self.counter].get("actionDescription")
if "myCondition" in str(action):
#set the popup structure
self.popup_B = ActivityBox(self)
self.popup_B.open()
# run the method in a thread
t1 = threading.Thread(target = timeConsumingMethod)
t1.start()
# dismiss the popup ActivityBox
self.popup_B.dismiss()
# call popup_A in thread
t3 = threading.Thread(target = self.popup_A)
t3.start()
def do(self):
self.counter = self.counter + 1
self.popup.dismiss()
self.goForward()
def cancel(self):
self.counter = self.counter + 1
self.popup.dismiss()
self.goForward()
def popup_A(self):
self.popup = MessageBox(self)
self.popup.open()
Builder.load_string()
中的 ActivityBox 和 MessageBox 弹出结构:
<MessageBox>:
size_hint: 1, .7
auto_dismiss: False
title: "MessageBoxTitle"
title_align: "center"
title_size: 30
BoxLayout:
orientation: "vertical"
Label:
font_size: '30sp'
text: "MessageBoxLabel"
BoxLayout:
orientation: "horizontal"
spacing: 10
size_hint: 1, .5
Button:
font_size: 50
background_color: 0,204,0,1
text: "CONFIRM"
on_press:
self.disabled = True
self.background_color = 0,255,0,1
app.do()
root.dismiss()
Button:
font_size: 50
background_color: 204,0,0,1
text: "CANCEL"
on_press:
self.background_color = 255,0,0,1
app.cancel()
root.dismiss()
<ActivityBox>:
size_hint: 1, .7
auto_dismiss: False
title: "ActivityBoxTitle"
title_align: "center"
title_size: 30
BoxLayout:
orientation: "vertical"
Label:
font_size: '30sp'
text: "ActivityBoxLabel"
BoxLayout:
orientation: "horizontal"
spacing: 10
size_hint: 1, .5
代码说明
主循环的组件是 goForward
和 popup_A。随着循环的每一段, popup_A 出现,在线程中调用。然后 popup_A 回调 goForward
。如果满足 goForward
中的条件“工作”,则显示“进行中的工作”popup_B。 popup_B 运行 与线程中的方法一起使用,否则 Kivy 不会显示弹出窗口(锁定 GUI)。
结果
到目前为止我已经尝试过:
- 运行 popup_B in a thread
t1 = threading.Thread(target = self.popup.open)
: popup_A 覆盖 popup_B. - 使用线程
.join()
:popup_A出现但popup_B不出现,.join()忽略它。 - 运行 popup_B 和
timeConsumingMethod
一起在一个线程中: popup_A 出现但 popup_B 没有出现。 - 运行
timeConsumingMethod
作为进程:popup_A 出现但 popup_B 不出现,程序挂起。 - 使用
mutex = threading.Lock()
锁定带有 popup_B 的线程:popup_A 出现在 popup_B 之上。 GUI 也会出现乱码。 - 运行 popup_A 不在一个线程中 运行 popup_B 和
timeConsumingMethod
一起在一个线程中: popup_A 出现popup_B.
问题
popup_A 只有在线程中的方法完成并且 popup_B 被关闭后才能显示。如何防止 popup_A 覆盖 popup_B?
我查看了下面的帖子,但没有找到解决方案。
--- 更新 20200715 -------------------------------- --------------
在代码中,我在 popup_B 中将弹出窗口重命名为“进行中”,在 popup_A[=87 中重命名弹出窗口 2 =] 以便更好地理解。
--- 更新 20200716 -------------------------------- --------------
我使用 Clock.schedule_once
修改了代码 step2
(线程 popup_A
和 step3
(线程 timeConsumingMethod
和 popup_B
). popup_B
上升但 popup_A
覆盖它直到最后一个 popup_A
被按钮关闭。等待 timeConsumingMethod
在没有 [=26= 的情况下完成] 启动,我使用 while loop
。代码如下:
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data["tasks"]): # check the counter
self.code = self.data["tasks"][self.counter].get("code")
action = self.data["tasks"][self.counter].get("actionDescription")
if "myCondition" in str(action):
self.returnStatus = 1 # set status
#the two rows below give the same result
#self.popup_B = ActivityBox(self)
#self.popup_B.open()
Clock.schedule_once(self.step3)
# run the method in a thread
t1 = threading.Thread(target = self.step1)
t1.start()
while self.returnStatus != 0:
time.sleep(1)
Cloch.schedule_once(self.step2)
def step1(self):
ts1 = threading.Thread(target = self.timeConsumingMethod)
ts1.start()
ts1.join()
self.returnStatus = 0 # change status when over
return(self.returnStatus)
def step2(self, *args):
ts2 = threading.Thread(target = self.popup_A)
ts2.start()
def step3(self, *args):
#set the popup structure
self.popup = ActivityBox(self)
self.popup.open()
def popup_A(self):
self.popup = MessageBox(self)
t3 = threading.Thread(target = self.popup.open)
t3.start()
def do(self):
self.counter = self.counter + 1
self.popup.dismiss()
self.goForward()
def cancel(self):
self.counter = self.counter + 1
self.popup.dismiss()
exit()
- Correct way to implement loading popup in kivy app
让 popup_A 在耗时线程完成之前不弹出的一种方法是在耗时线程结束时调用 popup_A。尝试将 goForward()
方法分成两部分。第一部分几乎没有变化:
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data["tasks"]): # check the counter
self.code = self.data["tasks"][self.counter].get("code")
action = self.data["tasks"][self.counter].get("actionDescription")
if "myCondition" in str(action):
#set the popup structure
self.popup_B = ActivityBox(self)
self.popup_B.open()
# run method in a thread
t1 = threading.Thread(target = self.timeConsumingMethod)
t1.start()
我已将 timeConsumingMethod()
移至 class,因此需要在 Thread
中调用 self.timeConsumingMethod
。
然后将其余的旧goForward()
方法放在一个单独的方法中(我称之为step2()
):
def step2(self, *args):
# dismiss the popup ActivityBox
self.popup_B.dismiss()
# call popup_A in thread
t3 = threading.Thread(target=self.popup_A)
t3.start()
然后在timeConsumingMethod()
中,完成后调用step2()
:
def timeConsumingMethod(self):
time.sleep(5)
Clock.schedule_once(self.step2)
解决方案
我已经使用线程解决了弹出窗口重叠的问题。我想问题出在共享内存和解释器锁上。
代码
我修改了代码并将 threading.Thread
添加到绑定到弹出窗口按钮的方法 do(self)
和 cancel(self)
中。 step1
在线程中运行 timeConsumingMethod
,step2
调用在线程中运行的 popup_A,step3
在线程中运行 popup_B一个线程。这样 popup_A 确实显示并在 popup_B 出现时被解雇。
def goForward(self):
if self.header == "someTask":
if "tasks" in self.data: # check if the request has "tasks" in the body
if self.counter < len(self.data): # check the counter
if "myCondition":
self.step3()
self.step1()
self.popup_A()
def step1(self):
self.popup_A.dismiss() # dismiss the popup A first
ts1 = threading.Thread(target = self.timeConsumingMethod)
ts1.start()
ts1.join()
self.popup_B.dismiss() # dismiss the popup B at the end
def step2(self, *args):
self.popup_A()
def step3(self, *args):
#set the popup structure
self.popup_B = ActivityBox(self)
ts3 = threading.Thread(target = self.popup_B.open)
ts3.start()
ts3.join()
def popup_A(self):
self.popup_A = MessageBox(self)
t3 = threading.Thread(target = self.popup_A.open)
t3.start()
def do(self):
self.counter = self.counter + 1
self.popup_A.dismiss() # dismiss the popup A first
td = threading.Thread(target = self.goForward)
td.start()
def cancel(self):
self.counter = self.counter + 1
self.popup_A.dismiss() # dismiss the popup A first
tc = threading.Thread(target = self.goForward)
tc.start()