IntVar().trace() не работает

Я только начинаю писать код на Python/Tkinter для небольшого плагина Pymol. Здесь я пытаюсь создать кнопку-переключатель и сообщать о ее статусе при нажатии. Кнопка перемещается вверх и вниз, но toggleAVA никогда не вызывается. Есть идеи, почему?

from Tkinter import *
import tkMessageBox

class AVAGnome:

    def __init__(self, master):
        # create frames
        self.F1 = Frame(rootGnome, padx=5, pady=5, bg='red')

        # checkbuttons
        self.AVAselected = IntVar()
        self.AVAselected.trace("w", self.toggleAVA)
        self.AVAbutton = Checkbutton(self.F1, text='AVA', indicatoron=0, variable=self.AVAselected)

        # start layout procedure
        self.layout()

    def layout(self):
        self.F1.pack(side=TOP, fill=BOTH, anchor=NW)

        #entry and buttons
        self.AVAbutton.pack(side=LEFT)

    def toggleAVA(self, *args):
        if (self.AVAselected.get()):
          avastatus = "selected"
        else:
          avastatus = "unselected"
        tkMessageBox.showinfo("AVA status", avastatus)

def __init__(self):
    open_GnomeUI()

def open_GnomeUI():
    # initialize window
    global rootGnome
    rootGnome = Tk()
    rootGnome.title('AVAGnome')
    global gnomeUI
    gnomeUI = AVAGnome(rootGnome)

person ipetrik    schedule 24.01.2017    source источник
comment
Checkbutton имеет вариант command=, поэтому, возможно, используйте command=self.toggleAVA вместо trace()   -  person furas    schedule 24.01.2017
comment
Да, но это всего лишь очень простой пример. Я могу изменить статус if self.AVAselected другим способом. В любом случае, я пытаюсь понять, почему функция, которая должна работать, не работает.   -  person ipetrik    schedule 24.01.2017
comment
Кроме того, я пробовал это (используя command), и статус self.AVAselected сообщается как unselected независимо от того, нажата кнопка или нет.   -  person ipetrik    schedule 24.01.2017
comment
Я попробовал ваш код, и он работает как отдельная программа. Я видел подобные проблемы с переменными в других программах, если программы использовали два Tk() и два mainloop(). Возможно, вам нужно просто использовать Toplevel() вместо Tk() для создания окна.   -  person furas    schedule 24.01.2017


Ответы (2)


Я протестировал ваш код с помощью Pymol.

Проблема в том, что вы используете Tk() для создания своего окна. Вы должны использовать Toplevel() и тогда он будет корректно работать с trace() или с command=.


Pymol создается с помощью tkinter, который может иметь только одно окно, созданное с помощью Tk() - это главное окно в программе. Каждое второе окно должно быть создано с помощью Toplevel().

person furas    schedule 24.01.2017
comment
Это было точно! Забавно, я пытался избежать подобных вещей, выпотрошив установленный плагин Pymol и наполнив его своей собственной функциональностью... видимо, там много живого грязного кода... - person ipetrik; 25.01.2017

Я прикрепил рабочую версию вашего кода ниже. Вы можете обратиться к нему, чтобы узнать, где вы ошиблись. Как правило, вы должны помнить о том, как вы структурируете свой код, если используете формат класса. Это поможет вам лучше визуализировать свой код и отлаживать его. Вы можете прочитать это обсуждение, чтобы помочь вам.

from Tkinter import *
import tkMessageBox

class AVAGnome(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)

        # create frames
        self.F1 = Frame(self, padx=5, pady=5, bg='red')

        # checkbutton 
        self.AVAselected = IntVar() 
        self.AVAselected.trace("w", self.toggleAVA)
        self.AVAbutton = Checkbutton(
            self.F1, text='AVA', indicatoron=0, width=10,
            variable=self.AVAselected)

        # start layout procedure
        self.F1.pack(side=TOP, fill=BOTH, anchor=NW)
        self.AVAbutton.pack(side=LEFT) #entry and buttons

    def toggleAVA(self, *args):
        if (self.AVAselected.get()):
          avastatus = "selected"
        else:
          avastatus = "unselected"
        tkMessageBox.showinfo("AVA status", avastatus)

if __name__ == '__main__':
    rootGnome = Tk()
    rootGnome.title('AVAGnome')
    gnomeUI = AVAGnome(rootGnome)
    gnomeUI.pack(fill="both", expand=True)
    gnomeUI.mainloop()

Обновление: приведенная выше структура кода предназначена для отдельной программы tkinter. Я пытаюсь преобразовать этот рабочий код, чтобы следовать примеру плагина Pymol. Пересмотренный код размещен ниже и подлежит дальнейшему пересмотру.

# https://pymolwiki.org/index.php/Plugins_Tutorial
# I adapted from the example in the above link and converted my previous code to
# 
from Tkinter import *
import tkMessageBox

def __init__(self): # The example had a self term here.
    self.open_GnomeUI()


class AVAGnome(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)

        # create frames
        self.F1 = Frame(self, padx=5, pady=5, bg='red')

        # checkbutton 
        self.AVAselected = IntVar() 
        self.AVAselected.trace("w", self.toggleAVA)
        self.AVAbutton = Checkbutton(
            self.F1, text='AVA', indicatoron=0, width=10,
            variable=self.AVAselected)

        # start layout procedure
        self.F1.pack(side=TOP, fill=BOTH, anchor=NW)
        self.AVAbutton.pack(side=LEFT) #entry and buttons

    def toggleAVA(self, *args):
        if (self.AVAselected.get()):
          avastatus = "selected"
        else:
          avastatus = "unselected"
        tkMessageBox.showinfo("AVA status", avastatus)

# Note, I added a "self" term throughout function. 
# Try w/ & w/o "self" to see which works. 
def open_GnomeUI(self): 
    self.rootGnome = Tk()
    self.rootGnome.title('AVAGnome')
    self.gnomeUI = AVAGnome(self.rootGnome)
    self.gnomeUI.pack(fill="both", expand=True)
    self.gnomeUI.mainloop()
person Sun Bear    schedule 24.01.2017
comment
OP создает не отдельную программу, а плагин для Pymol, для которого может потребоваться другая структура - для его запуска может потребоваться функция __init__ (но я не уверен) - person furas; 24.01.2017
comment
@furas Спасибо за указание. Виноват. Сказав это, я посмотрел на пример плагина Pymol и попытался преобразовать рабочий код, чтобы следовать примеру. Надеюсь это работает. Я бы ожидал, что сначала возникнут проблемы с интерфейсом, иначе я думаю, что раздел класса должен работать как есть. Нужен ипетрик для обратной связи, если получится. Размещение исправленного кода выше. - person Sun Bear; 24.01.2017
comment
@Sun Bear - Спасибо. В настоящее время не работает как опубликовано, но это связано с инициализацией. Я поработаю и заставлю это работать с классом, который вы предоставили, и пойду оттуда. - person ipetrik; 24.01.2017
comment
P.S. Ваш первый код работает как отдельная программа на Python, так что это начало. - person ipetrik; 24.01.2017