2

I'm just getting started coding in Python/Tkinter for a small Pymol plugin. Here I'm trying to have a toggle button and report its status when it is clicked. The button goes up and down, but toggleAVA never gets called. Any ideas why?

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)
ipetrik
  • 1,749
  • 18
  • 28
  • `Checkbutton` has option `command=` so maybe use `command=self.toggleAVA` instead of `trace()` – furas Jan 24 '17 at 13:45
  • Yes, but this is just a very basic example. I may wish to change the status if `self.AVAselected` by another means. In any case, I'm trying to understand why a functionality that should work doesn't – ipetrik Jan 24 '17 at 18:59
  • Also, I did try that (using `command`), and the status of `self.AVAselected` is reported as `unselected` regardless of the button being up or down. – ipetrik Jan 24 '17 at 19:00
  • I tried your code and it works as standalone program. I saw similar problems with variables in other programs if programs used two `Tk()` and two `mainloop()`. Maybe you have to simple use `Toplevel()` instead `Tk()` to create window. – furas Jan 24 '17 at 19:12

2 Answers2

4

I tested your code with Pymol.

Problem is because you use Tk() to create your window. You have to use Toplevel() and then it will work correctly with trace() or with command=.


Pymol is created with tkinter which can have only one window created with Tk() - it is main window in program. Every other window has to be created with Toplevel().

furas
  • 134,197
  • 12
  • 106
  • 148
  • That was it exactly! Funny, I tried to avoid things like that by gutting an established Pymol plugin and filling it in with my own functionality... apparently there's a lot of live dirty code... – ipetrik Jan 25 '17 at 00:10
1

I have attached a working version of your code below. You can refer to it to learn where you went wrong. Generally, you have to mind how you structure your code if you are using a class format.This will help you visualize your code and debug better. You can read this discussion to help you.

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

Update: The above code structure is for standalone tkinter programme. I am attempting to convert this working code to follow Pymol plugin example. Revised code is posted below and is susceptible to further revision.

# 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()
Community
  • 1
  • 1
Sun Bear
  • 7,594
  • 11
  • 56
  • 102
  • 1
    OP doesn't create standalone program but plugin for Pymol which may need different structute - it may need function `__init__` to run it.(but I'm not sure) – furas Jan 24 '17 at 13:31
  • @furas Thanks for pointing out. My bad. Having said that, I have looked at an Pymol plugin example and have tried to convert the working code to follow the example. I hope it works. I would expect some interfacing issue initially, else I think the class section should work as is. Will need ipetrik to feedback if it work. Posting the revised code above. – Sun Bear Jan 24 '17 at 18:03
  • @Sun Bear - Thanks. Doesn't currently work as posted, but it has to do with the initialization. I'll tinker and get that to work with the class you provided and go from there. – ipetrik Jan 24 '17 at 19:04
  • P.S. Your first code does work as a standalone python program, so that's a start. – ipetrik Jan 24 '17 at 19:07