【问题标题】:Kivy - popup A shows over popup BKivy - 弹出窗口 A 显示在弹出窗口 B 上
【发布时间】:2020-07-14 10:43:07
【问题描述】:

问题

我有一个循环,在每个段落中都会显示一个弹出窗口。我将其称为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 中的条件“work”,则会显示“work in progress”popup_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_A 只能在线程中的方法完成并且 popup_B 被解除后才会出现。如何防止 popup_A 覆盖 popup_B?

我查看了下面的帖子,但没有找到解决方案。

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

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

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

我使用Clock.schedule_once 修改了代码,用于step2(用于popup_Astep3 的线程(用于timeConsumingMethodpopup_B 的线程)。popup_B 上升但popup_A 覆盖直到最后一个popup_A 被按钮关闭。要等待timeConsumingMethod 完成而不启动popup_A,我使用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()
  1. Correct way to implement loading popup in kivy app
  2. Kivy: Dismiss One Popup From Another Popup
  3. Kivy Clock and Popup

【问题讨论】:

    标签: python multithreading popup kivy


    【解决方案1】:

    在耗时线程完成之前让 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() 移入班级,因此需要在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)
    

    【讨论】:

    • 您的方法很有趣,但流程必须保持在循环中。 popup_A 必须出现在每个段落中。根据您的建议,如果不满足 condition3,popup_A 不会显示。
    • 也许只是将else: 块添加到调用self.step2()if "myCondition" in str(action): 块中。当然,这需要小心处理self.popup_B 尚未创建的情况。
    • 我听从了@John Anderson 的建议,并按步骤划分了循环。这样做我来到了TypeError: step2() takes 1 positional argument but 2 were given. 请参阅更新 20200716。
    • 在此处发布的更新代码中,step2() 接受任意数量的位置参数,而不仅仅是 1。
    • 是的,它需要任意数量的位置参数来避免 TypeError。
    【解决方案2】:

    解决方案

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

    代码

    我修改了代码并将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()
    

    【讨论】:

      猜你喜欢
      • 2020-10-12
      • 1970-01-01
      • 2022-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多