Getting the value of a checkbox - python

This is code I found when searching to understand and learn about Tkinter, but it gives an error on check box toggle.
from Tkinter import *
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Windows")
Label(text="Contact List").grid(row=0,column=0,columnspan=2)
Text(width=30,height=15).grid(row=1,rowspan=9, column=0,columnspan=2,padx=20)
Button(text="Display Contact").grid(row=10, column=0,columnspan=2,pady=10)
Label(text="Last Name:").grid(row=11, column=0,pady=10)
Entry().grid(row=11,column=1)
Button(text="Search").grid(row=12,column=0,columnspan=2)
Label(text="New Contact").grid(row=0,column=2,columnspan=2)
Label(text="First Name:").grid(row=1,column=2,sticky=E)
Entry().grid(row=1,column=3)
Label(text="Last Name:").grid(row=2,column=2,sticky=E)
Entry().grid(row=2,column=3)
Label(text="Phone #:").grid(row=3,column=2,sticky=E)
Entry().grid(row=3,column=3)
friend_check = IntVar()
Checkbutton(variable=friend_check, command = self.friend_box, onvalue=1, offvalue=0, text = "Friend").grid(row=4,column=3,sticky=W)
#Label(text="Friend").grid(row=4,column=3,padx=20,sticky=W)
Label(text="Email:").grid(row=5,column=2,sticky=E)
Entry().grid(row=5,column=3)
Label(text="Birthday:").grid(row=6,column=2,sticky=E)
Entry().grid(row=6,column=3)
Button(text="Add Contact").grid(row=7,column=3,sticky=E)
def friend_box(self):
if self.friend_check.get() == 1:
print '1'
else:
print '0'
def main():
root = Tk()
root.geometry("600x450+900+300")
root.resizable(0,0)
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
This is the error mentioned above:
AttributeError: Example instance has no attribute 'friend_check'
Exception in Tkinter callback
How can I avoid this error?

You're taking too many shortcuts in your code. Let's look at an example:
Label(text="Contact List").grid(row=0,column=0,columnspan=2)
This creates a Label, but doesn't save a reference to it. It will display in the GUI, but if you ever want to refer back to it, you'll be unable to. This is important when you have something like an Entry widget, to which you're pretty much guaranteed to want to use again (for the get()).
Another issue is that you have the geometry management chained to the widget creation. If you did save a reference to this, it would simply point to None, which is the value returned by geometry management methods.
To fix this, unchain the statements and save a reference:
self.cl_label = Label(text="Contact List")
self.cl_label.grid(row=0,column=0,columnspan=2)
Do this for each widget you create.
For friend_check, you need to make it an instance variable instead of a local variable, as local variables are not usable outside their scope and get discarded when the containing function ends. Do this by prepending self. to the reference name.
self.friend_check = IntVar()

Related

Error when creating a Toplevel widget in Python

I'm coding an application to control serial connected device, right now I'm stuck in a GUI error, here is the simplified code:
import Tkinter
class PaginaPrincipale(Tkinter.Tk):
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
def connetti():
pagina_connessione=Tkinter.Toplevel()
pagina_connessione.title("Gestione connessione")
pagina_connessione.mainloop()
self.parent = parent
self.grid()
self.gestisci_connessione = Tkinter.Button(self, text="Connetti!", command=connetti)
self.gestisci_connessione.grid(row=0, column=0, sticky='EW')
if __name__ == "__main__":
applicazione = PaginaPrincipale(None)
applicazione.title = 'Pannello di controllo'
applicazione.mainloop()
When I run the program I get this error:TypeError: 'str' object is not callable
I'm new to Python2.7, I hope someone could tell me what I did wrong!
The widget has a method named title, which you can use to set the title. However, you are replacing this function with a string when you do this:
applicazione.title = 'Pannello di controllo'
Once you've done that, any subsequent attempt to call the function title will result in the error you get (ie: you can't "call" a string).
Instead, you need to call title as a function:
applicazione.title('Pannello di controllo')

Tkinter Button unable to find callback command

I'm working on a program that reads and parses a config file for an embedded hardware system I'm working on. I'm trying to use tkinter and python to make a simple GUI for reading and writing this file. I have the file IO and parsing mostly working, but I'm having trouble getting all the parts integrated with the GUI. I want to read the information off of the device and then populate the entry fields with the relevant info. The problem that I'm having is I keep getting the error
"in initUI
opnBut = Button(butFrm, text="Open", command=openCfg)
NameError: name 'openCfg' is not defined"
I can get it to find the function if I put it outside the Application class but then I can't figure out how to reference the fields inside the window I've made to update them.
Any help would be greatly appreciated. My code segment is included below.
class Application(Frame):
def openCfg():
name = getNameFromFile()
nameEntry.insert(0, name)
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Config Reader")
self.pack(fill=BOTH, expand=True)
nameFrm = Frame(self)
nameFrm.pack(fill=X)
nameLbl = Label(nameFrm, text="Device Name",width=20)
nameLbl.pack(side=LEFT,padx=5, pady=5)
nameEntry = Entry(nameFrm)
nameEntry.pack(fill=X, padx=5, pady=5)
butFrm = Frame(self)
butFrm.pack(fill=X)
opnBut = Button(butFrm, text="Open Cfg", command=openCfg)
opnBut.pack(fill=X, padx=5,pady=5)
root = Tk()
root.geometry("600x600")
app = Application(root)
app.mainloop()
items which are defined in the class namespace are bound to the class. In this case, you have a couple options...
One option is that you could make it a staticmethod:
class Application(Frame):
#staticmethod
def openCfg():
name = getNameFromFile()
nameEntry.insert(0, name)
And then bind the button as:
opnBut = Button(butFrm, text="Open Cfg", command=self.openCfg)
However, staticmethods are rarely necessary. In this case, I might just move the definition of openCfg out of the class and keep everything else as it is:
def openCfg():
name = getNameFromFile()
nameEntry.insert(0, name)
class Application(Frame):
...
On a second look, this will probably still bring up a NameError for nameEntry. You'll probably want a first-class method:
class Application(Frame):
def openCfg(self):
name = getNameFromFile()
self.nameEntry.insert(0, name)
And of course, when you create nameEntry, you'll need to make it a member of the Application class.
...
self.nameEntry = Entry(nameFrm)
self.nameEntry.pack(fill=X, padx=5, pady=5)
...

TKInter checkbox variable is always 0

I'm using Python's TkInter module for a GUI. Below is a simple checkbox code.
def getCheckVal():
print cbVar.get()
windowTime=Tk.Tk()
cbVar = Tk.IntVar()
btnC = Tk.Checkbutton(windowTime, text="Save", variable = cbVar, command=getCheckVal)
btnC.grid()
windowTime.mainloop()
This code works fine. Each time I tick the checkbox, I get 1, else 0.
However, when I run the same code in a function that is called from another TkInter command (when a button is pressed), it stops working. I always get 0 as the value.
class GUIMainClass:
def __init__(self):
'''Create the main window'''
self.window = Tk.Tk()
def askUser(self):
def getCheckVal():
print cbVar.get()
windowTime=Tk.Tk()
cbVar = Tk.IntVar()
btnC = Tk.Checkbutton(windowTime, text="Save", variable = cbVar,
command=getCheckVal)
btnC.grid()
windowTime.mainloop()
def cmdWindow(self):
frameShow=Tk.Frame(self.window)
frameShow.grid()
btnSwitch = Tk.Button(frameShow, text='Show Plots', command=self.askUser)
btnSwitch.grid()
self.window.mainloop()
GUIObj=GUIMainClass()
GUIObj.cmdWindow()
This is very unusual. What could be going wrong?
EDIT: I've used 2 mainloops because I want a separate window (windowTime) to open up when I click "Show Plots" button. This new window should have the checkbox in it.
Your windowTime, cbVar, etc. variables are defined in the function's local scope. When askUser() completes execution, those values are thrown away. Prepend self. to them to save them as instance variables.
There should only be one mainloop() in your program, to run the main Tkinter root object. Try putting it as the very last line in the program. I recommend doing some reading on Effbot for how to set up a Tkinter application.
I'm not sure what all you're trying to do, but one problem is that the TK.IntVar called cbVar that you create in your askUser() method will be deleted when the function returns, so you need to attach it to something that will still exist after that happens. While you could make it a global variable, a better choice would be to make it an attribute of something more persistent and has a longer "lifespan".
Another likely issue is that generally there should only be one call to mainloop() in a single Tkinter application. It appears what you want to do is display what is commonly known as a Dialog Window, which Tkinter also supports. There's some standard ones built-in, plus some more generic classes to simplify creating custom ones. Here's some documentation I found which describes them in some detail. You may also find it helpful to look at their source code.
In Python 2 it's in the /Lib/lib-tk/tkSimpleDialog.py file and
in Python 3 the code's in a file named /Lib/tkinter/simpledialog.py.
Below is code that takes the latter approach and derives a custom dialog class named GUIButtonDialog from the generic one included the Tkinter library which is simply named Dialog.
try:
import Tkinter as Tk # Python 2
from tkSimpleDialog import Dialog
except ModuleNotFoundError:
import tkinter as Tk # Python 3
from tkinter.simpledialog import Dialog
class GUIButtonDialog(Dialog):
"""Custom one Button dialog box."""
def __init__(self, btnText, parent=None, title=None):
self.btnText = btnText
Dialog.__init__(self, parent, title)
def getCheckVal(self):
print(self.cbVar.get())
def body(self, master):
"""Create dialog body."""
self.cbVar = Tk.IntVar()
self.btnC = Tk.Checkbutton(master, text=self.btnText, variable=self.cbVar,
command=self.getCheckVal)
self.btnC.grid()
return self.btnC # Return the widget to get inital focus.
def buttonbox(self):
# Overridden to suppress default "OK" and "Cancel" buttons.
pass
class GUIMainClass:
def __init__(self):
"""Create the main window."""
self.window = Tk.Tk()
def askUser(self):
"""Display custom dialog window (until user closes it)."""
GUIButtonDialog("Save", parent=self.window)
def cmdWindow(self):
frameShow = Tk.Frame(self.window)
frameShow.grid()
btnSwitch = Tk.Button(frameShow, text='Show Plots', command=self.askUser)
btnSwitch.grid()
self.window.mainloop()
GUIObj = GUIMainClass()
GUIObj.cmdWindow()

python - A strange problem when I'm trying to display an image in the Toplevel widget

I'm using Python(2.5) to make a "web album viewer".
I use Tkinter to write GUI, urllib2 to fetch the image from web, PIL to handle the image
User would click a button, and then it would create a Toplevel widget, download the picture, and display it in the Toplevel widget.
The button is bound to the "look" method.
So the code is like this:
class App:
#some codes are omitted here
def look(self, pic_url):
top = Toplevel()
more = More(top, pic_url)
class More:
def __init__(self, master, pic_url):
self.frame = Frame(master)
self.frame.pack()
response = urllib2.urlopen(pic_url)
open("inner_temp.jpg", "wb+").write(response.read())
self.picture = ImageTk.PhotoImage(file = "inner_temp.jpg")
self.photo_label = Label(self.frame, image = self.picture)
self.photo_label.pack()
The Toplevel widget showed, but there's nothing inside. I found "inner_temp.jpg" was downloaded in the folder correctly, but it just didn't show.
But the strangest thing is if I type one whatever character in the end of the code, the console window would show error message, but the picture showed in the Toplevel widget!
def look(self, pic_url):
top = Toplevel()
more = More(top, pic_url)
class More:
def __init__(self, master, pic_url):
self.frame = Frame(master)
self.frame.pack()
response = urllib2.urlopen(pic_url)
open("inner_temp.jpg", "wb+").write(response.read())
self.picture = ImageTk.PhotoImage(file = "inner_temp.jpg")
self.photo_label = Label(self.frame, image = self.picture)
self.photo_label.pack()
x
NameError: global name 'x' is not defined
How could this happen!? I really can't figure it out!
Can someone help me?
Thanks, and I'm sorry for my poor English.
Without seeing more code, my guess is that you are neglecting to start the event loop, which is necessary for widgets to refresh themselves. When you add the code that throws an error, that error triggers the event loop which causes the window to refresh.
My guess would be garbage collection.
Try something like this:
class More:
def __init__(self, master, pic_url):
self.frame = Frame(master)
self.frame.pack()
response = urllib2.urlopen(pic_url)
open("inner_temp.jpg", "wb+").write(response.read())
self.frame.picture = ImageTk.PhotoImage(file = "inner_temp.jpg")
self.photo_label = Label(self.frame, image = self.frame.picture)
self.photo_label.pack()
Thank you all very much! Your answers and comments help me solve the problem.
I finally found the problem!
The problem is here:
this code
class App:
#some codes are omitted here
def look(self, pic_url):
top = Toplevel()
more = More(top, pic_url)
should be
class App:
#some codes are omitted here
def look(self, pic_url):
top = Toplevel()
self.more = More(top, pic_url)
Although I'm not familiar with the garbage collection mechanism of Python, I think the reason why the picture only shows if the error happens is because the error stops the garbage collection from clearing some part of the local variable "more". And replacing the local variable with instance variable "self.more" solves this problem!

{PYTHON + TKINTER} "Type cast" problem: How to retrieve Custom frame objects from a Pmw.NoteBook?

I am writing a GUI Python application.
I am using Tkinter + PythonMegaWidgets for semplicity reasons.
Going straight to the point, I need to extend Tkinter.Frame baseclass, by adding some custom member functions which provides extra-functionalities.
These "Custom Frames" will be added to single tabs of a Pmw.NoteBook object.
Official related docs can be found at: http://pmw.sourceforge.net/doc/NoteBook.html
Later, I need to retrieve "Custom Frame" instances from NoteBook, invoking custom member functions that I have added; here the problems begins...
despite the principle of Duck Typing, I can not access ANY of these "extra-methods" because the methods of Pmw.NoteBook class can only return Frame objects!.
I can not find any solution.
Below a piece of sample (more simplified) code which describes in detail my issue.
from Tkinter import *
from Pmw import NoteBook
# I define a custom frame, by extending Tkinter.Frame baseclass
class CustomPanel(Frame):
def __init__(self, master, _text):
Frame.__init__(self, master)
self.label = Label(self, text=_text)
self.localVariable = "Hello, world!" # I define a new local variable
self.label.pack()
self.pack()
# I define a custom member function, which I _ABSOLUTELY_ want to be accessible.
def customMethod(self):
print self.localVariable
# main frame of application
class MyFrame(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.noteBook = NoteBook(self) # I create a NoteBook object...
tab1 = self.noteBook.add("tab 1") # then, I add one (empty) tabs to it
panel1 = CustomPanel(tab1, "hello")
self.button = Button(self, text="Call CustomMethod()!", command=self.callCustomMethod) # I add a button test
self.noteBook.grid()
self.button.grid(row=1)
self.pack()
self.mainloop()
# I define click handler for button,
def callCustomMethod(self):
panel1 = self.noteBook.page(0) # I try to get frame contained in current tab
# pane11 is supposed to be a 'CustomPanel' object;
try:
panel1.customMethod() # ...then, custom method should be accessible
except AttributeError:
print 'AttributeError!'
# for illustration purpose only, I show that Panel1 is a 'Frame'(superclass) object only!
print panel1.__class__
frame = MyFrame() # create a MyFrame instance
Pressing the button, console output is:
AttributeError!
Tkinter.Frame
to anticipate objections:
1- Set panel1.class attribute, as showed below,
try:
panel1.__class__ = CustomPanel
panel1.customMethod() # ...then, custom method should be accessible
except AttributeError:
print 'AttributeError!'
DON'T work, because customMethod() could not access in any case to localVariable, which is declared in CustomPanel subclass only;
2- I can not even recall CustomPanel constructor, because this will RESET original member variables, which I want to retrieve with their original values.
Any help is appreciated.
IT
I don't think you need to change the class of the notebook tab, you can just add your custom frame inside that tab. Just tell the frame what your inner frame is, and remember to pack your inner frame inside the tab frame.
For example:
class MyFrame(Frame):
def __init__(self, master=None):
...
panel1 = CustomPanel(tab1, "hello")
panel1.pack(fill="both", expand=True)
tab1.inner_panel = panel1
...
def callCustomMethod(self):
tab1 = self.noteBook.page(0)
panel1 = tab1.inner_panel
...

Categories