Kivy - всплывающее окно A отображается поверх всплывающего окна B - PullRequest
0 голосов
/ 14 июля 2020

ПРОБЛЕМА

У меня есть все oop, которые в каждом отрывке отображают всплывающее окно. Я назову это popup_A. В l oop есть условие, при котором он запускает вместе другое всплывающее окно и метод в потоке. Это второе всплывающее окно я называю 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

CODE Метод, участвующий в цикле:

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()

Структура всплывающих окон ActivityBox и MessageBox в the Builder.load_string():

<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

ОБЪЯСНЕНИЕ КОДА Компонентами основного l oop являются goForward и popup_A. При каждом проходе l oop появляется popup_A, вызываемое в потоке. Затем popup_A перезванивает goForward. Если условие «работа» в goForward выполняется, появляется всплывающее окно «работа в процессе». Popup_B запускается вместе с методом в потоке, иначе Kivy не отображает всплывающее окно (блокировка GUI).

РЕЗУЛЬТАТЫ

До сих пор я пробовал использовать:

  1. Запуск popup_B в потоке t1 = threading.Thread(target = self.popup.open): 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 и popup2 в popup_A для лучшего понимания.

--- ОБНОВЛЕНИЕ 20200716 ------------------------------------------------ -

Я изменил код, используя Clock.schedule_once для step2 (поток для popup_A и step3 (поток для timeConsumingMethod и popup_B). popup_B идет вверх, но popup_A закрывает его до тех пор, пока последний popup_A не будет отключен кнопкой. Чтобы дождаться, пока timeConsumingMethod закончит sh без запуска 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. Правильный способ реализации всплывающего окна загрузки в приложении kivy
  2. Kivy: отклонить одно всплывающее окно из другого всплывающего окна
  3. Часы Kivy и всплывающее окно

Ответы [ 2 ]

0 голосов
/ 22 июля 2020

РЕШЕНИЕ

Я решил проблему перекрытия всплывающих окон с использованием потоковой передачи. Я предполагаю, что проблема связана с разделением памяти и блокировкой интерпретатора.

КОД

Я изменил код и добавил 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()
0 голосов
/ 14 июля 2020

Способ заставить 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)
...