2017-04-05 2 views
0

저는 tkinter를 사용하여 GUI를 다이얼링하고 있습니다. 응용 프로그램이 닫히면 모든 스레드를 정리하여 책임있는 시민이 되고자합니다. 내 응용 프로그램은 폴링 엔진이 정기적으로 업데이트를 내 디스플레이에 다시 보내는 멀티 스레드입니다. 공유 리소스에 대한 액세스를 제어하기 위해 리소스 잠금을 사용하고 있습니다 (아래의 예제 코드에는 표시되지 않음). 문제는 응용 프로그램 창을 닫은 후 꽤 자주 남은 스레드가 붙어 있다는 것입니다.tkinter (파이썬 GUI) 위젯을 제거하는 호출이 걸려 있습니다.

아래 코드에서 내가 작업하고있는 것을 보여 주려고했습니다. "업데이트"콜백이 비동기입니다. 문제는 기본 위젯의 상태에 대해 "self._active"를 확인한 시간과 "... frameWidget.configure (style = ..."및 "..." varToUpdate.set (... "), 위젯의 상태가 tkinter 엔진에 의해 'defunct'/ 'unresponsive'의 일부 풍으로 변경되었을 수 있습니다 ..

잠금을 사용하면 도움이되지 않습니다. 방법을 정리할 때까지 위젯의 상태를 제어하여 '죽어가는'일이 없도록합니다. 이벤트 알림은 간단히 나타납니다. 이벤트가 발생했음을 알려주지 만 위젯을 지연시키지 않습니다. 청소를 마칠 때까지 '죽음'

실제 문제는 위젯의 스타일을 구성하는 호출 ("self.frameWidget.configure (style = stylename) ") 및 IntVar ("self.varToUpdate.set (value) ")를 업데이트하려면 GUI가 종료 될 때 단순히 멈추거나 차단하십시오.
예외를 생성하거나 아무 것도 산출하지 않고 이러한 메서드 호출이 반환되지 않습니다. (이것은 나에게 좋은 행동처럼 보이지 않습니다.)

그래서. 이 문제를 어떻게 처리할까요? 어떤 아이디어? 어떻게 든 "원자"라는 코드 덩어리를 지정하는 것을 좋아해서 객체 조작이 "._active"에 대한 검사가 끝난 직후에 실행되도록 보장 할 수 있었지만 Python에서 그런 것을 보지 못했습니다. . 이를 달성 할 수 있다고해도, tkinker 엔진이 실제로 오브젝트를 업데이트하는 방법에 대해 확신하지 못하기 때문에 문제가 해결되지 않을 수 있습니다. 내가 놓친 게 있니?

그렇습니다. 저는 파이썬을 처음 접했습니다. bla bla bla ... 저는 자바 배경에서 왔기 때문에, 필자가 작성한 것 중 많은 부분이 확실히 "파이썬이 아닌 것"이라고 가정합니다. 나는 언어의 강점을 활용하기 위해 어떻게 개선 할 수 있는지에 대한 당신의 통찰력을 듣게되어 매우 기쁩니다.

예제 코드! 데몬이 잘

t = Thread(target=self.pollData) 
t.daemon = True 
t.start() 

스레드 't'를 작업으로 메인 스레드가

이 난 아직도/매달려를 차단함으로써 Tkinter의 방법이 제대로 작동하는지 느낌이 종료 할 때

from tkinter import * 
from tkinter import ttk 
from myutil import Subscriber 

threshold = 20 
deactivationEvents = ("Deactivate", "Destroy", "Unmap") 
activationEvents = ("Activate", "Map") 

# class implements/inherits "listener pattern" functionality 
class MyClass(Subscriber) 
    def __init__(self, parentWidget): 
    self._active = False 
    self.frame = ttk.LabelFrame(parentWidget, text='something') 
    self.varToUpdate = IntVar() 
    self.bar = ttk.Progressbar(self.frame, orient=VERTICAL) 
    self.bar.config(mode='determinate', maximum=100, variable=self.varToUpdate) 
    self.moreThings() 
    self.bindWidgetEvents(): 

    . more 
    . code 
    . here 

    # I'm using a simple boolean flag to control access here 
    # I've tried using threading.Lock as well, to no avail 
    def update(self, value): 
    stylename = "{}.TFrame".format("Normal" if value > threshold else "Alarm") 
    if self._active: 
     self.frame.configure(style=stylename) 
     self.varToUpdate.set(value) 

    def bindWidgetEvents(self): 
    widgets = [self.bar, self.frame] 
    self.bindActivationEvents(widgets) 
    self.bindDeactivationEvents(widgets) 

    def bindActivationEvents(self, widgets): 
    def activate(event): 
     self._active = True 
    for widget in widgets: 
     for event in activationEvents: 
     widget.bind("<{}>".format(event), activate) 

    def bindDeactivationEvents(self, widgets): 
    def deactivate(event): 
     self._active = False 
    for widget in widgets: 
     for event in deactivationEvents: 
     widget.bind("<{}>".format(event), deactivate) 
+0

스레드 스레드 데몬을 만들어 상위 스레드와 함께 죽게하십시오. – Novel

+0

글쎄, 그건 분명히 효과가있다! 나는 아직도 그 방법들이 매달리기보다는 예외를 제기해야한다고 생각한다. 고마워요! –

답변

0

배경 스레드를 종료 설정 이 시나리오에서 예외를 발생시키기보다는

0

데몬으로 스레드를 할당하는 것이이 특별한 경우에 효과적이지만 실제로 그렇게하지 않으면 도움이되지 않습니다. 실제로 응용 프로그램을 닫습니다. 내가 창문이나 프레임을 닫는 것일까? 그렇다면 우리는 이러한 불명예스러운 GUI 항목의 메소드가 호출되고 스레드가 걸려있는 메소드의 문제에 갇혀 있습니다 ...

이러한 메소드가 호출되지 않도록하는 방법이 필요하지만 검사에 의존 할 수는 없습니다 왜냐하면 이것들은 원자 적 연산이 아니기 때문입니다.

다른 아이디어가 있습니다. 사람들이 이것을 해결책으로 생각하는 이유는 무엇입니까?

우리는 또한 단순히 개체를 삭제하고 호출이 현재 존재하지 않는 개체를 만들 때 결과 예외를 잡아 처리 추가 할 수 있습니다
# The tkinter GUI objects were hanging indefinitely upon calls to their methods after 
    # the window was closed, so we will replace them with dummy objects that will recieve 
    # those calls instead 
    def deactivate(self): 
    self._active = False 
    self.varToUpdate = Stub() # we could probably just reinitialize an IntVar 
    self.bar = Stub() 
    self.frame = Stub() 

class Stub(object): 

    def __init__(self): 
    pass 

    def config(self, **kwargs): 
    pass 

    def set(self, value): 
    pass 

...

def deactivate(self): 
    self._active = False 
    del self.varToUpdate 
    del self.bar 
    del self.frame 

불행하게도, 심지어 이러한 솔루션으로, 나는 여전히 GUI 개체에 대한 호출이 이루어진 후에 개체의 종료가 발생할 수있는 기회가 있다고 생각합니다.