Kivy-弹出式窗口A显示在弹出式窗口B之上

时间:2020-07-14 10:43:07

标签: python multithreading popup kivy

问题

我有一个循环,在每个段落中都显示一个弹出窗口。我将其称为popup_A。在循环中,有一个条件,当被满足时,它会同时触发另一个弹出窗口和一个线程中的方法。第二个弹出窗口我称为popup_B。问题是它确实显示了popup_B,但是紧接着popup_A显示在popup_B之上,完全覆盖了它。为了更好地描绘图片,请了解流程的想法:

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中的条件“工作”,则显示“正在进行的工作”弹出窗口B。 popup_B与方法一起在线程中运行,否则Kivy不会显示弹出窗口(锁定GUI)。

结果

到目前为止,我已经尝试过:

  1. 在线程t1 = threading.Thread(target = self.popup.open)中运行popup_B:popup_A涵盖了popup_B。
  2. 使用线程.join():出现popup_A但没有popup_B,.join()忽略它。
  3. 在线程中同时运行popup_B和timeConsumingMethod:出现popup_A但没有popup_B。
  4. 运行timeConsumingMethod作为一个过程:出现popup_A但没有popup_B,程序挂起。
  5. 使用mutex = threading.Lock()用popup_B锁定线程:popup_A出现在popup_B上方。同样,GUI也出现乱码。
  6. 不在线程中运行popup_A并在线程中同时运行popup_B和timeConsumingMethod:popup_A出现在popup_B上方。

问题

仅当线程中的方法完成并且popup_B被关闭后,popup_A才能显示。如何防止popup_A覆盖popup_B?

我翻阅了下面的帖子,但没有找到解决方法。

---更新20200715 --------------------------------------- ---------

在代码中,我将 popup_B 中的弹出窗口重命名为“正在进行中”,并在 popup_A 中将popup2重命名为更好的理解。

---更新20200716 --------------------------------------- ----------

我使用Clock.schedule_once的{​​{1}}(step2popup_Astep3timeConsumingMethod的线程)修改了代码。 popup_B上升,但popup_B覆盖直到用按钮关闭最后一个popup_A为止,等待popup_A完成而timeConsumingMethod结束开火,我使用popup_A。代码如下:

while loop
  1. Correct way to implement loading popup in kivy app
  2. Kivy: Dismiss One Popup From Another Popup
  3. Kivy Clock and Popup

2 个答案:

答案 0 :(得分:0)

使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()移到了班级,因此需要在self.timeConsumingMethod中以Thread的身份进行呼叫。

然后将其余的旧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)

答案 1 :(得分:0)

解决方案

我已经通过使用线程解决了弹出窗口重叠的问题。我想这是共享内存和解释器锁的问题。

代码

我修改了代码,并将threading.Thread添加到绑定到弹出按钮上的方法do(self)cancel(self)中。 step1在线程中运行timeConsumingMethodstep2调用在线程中运行的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()