python tkinter module Label widget wrapped in oop - python

I am practicing on my personal project to create oop from tkinter module. I have written a code block where I try to create Label widget by imperative code line, then within a class.
from tkinter import *
app=Tk()
app.geometry('500x300')
Button(app,width=13,height=1,text='scrape').pack()
var_str=StringVar()
var_str='result 001 ...'
Label(app,width=33,height=1,text='res',textvariable=var_str).pack()
class label():
def __init__(self,master,var_text):
self.label=Label(master,width=33,height=1,textvariable=var_text).pack()
lbl_one=label(app,var_str)
app.mainloop()
The strangeness is if I comment out Label(app,width=33,height=1,text='res',textvariable=var_str).pack() then my object instantiation does not work out.
I would like to have a clear answer why lbl_one object gives same text result as with Label(app...) line?

because you probably forgot that u put StringVar at top then changed it to string which not work.
var_str=StringVar(master=app, value="res")
replace that line to this and comment the first label's line then the object would work fine.

Related

tkinter checkbutton not displaying correct value when class imported from other file

I have a main program which does some cool stuff and I am currently setting up a 'settings editor' to let the user change some GUI related stuff and default values. It reads values from a text file, which is read in correctly and saves them to a dictionary self.propertiesDict. Some of the options are on/off switches, so I use checkbuttons for them. What is puzzling me is following behavior: the code works perfectly fine, when I execute the settingsEditor.py (the script creating the settings window) directly. All the checkbuttons are set to active / True. However, when I include my settingsEditor in my main program and call it, it creates fine but all the checkbuttons show the wrong value: False. I read a lot of topics here to find an answer, but I think I avoided the most common errors:
I use the tk variables
tk variables are created and set prior to the buttons
variables are not only in local scope (prefixed self.)
As you can see, I tried with an IntVar and a BooleanVar, but neither is working correctly. Something else is strange, when I use ttk.checkbuttons, I get the issue described here. I use Visual Studio for debugging and I can't see any difference in the process when going trough line by line, except for the wrong display result. I am happy for any suggestion. Sorry for not providing a full MWE, I will do, if nobody can help me from this here.
settingsEditor.py
import tkinter as tk
from tkinter import ttk
...
class mySettingsEditor:
def __init__(self):
...
def createGUI(self):
# Show main options on startup on/off
self.showOptionsVar = tk.IntVar()
self.showOptionsVar.set(str2int(self.propertiesDict['showMainOptionsExpanded']))
print(self.showOptionsVar.get())
self.checkBtn1 = tk.Checkbutton(Frame, text='Main Options Section', variable=self.showOptionsVar)
self.checkBtn1.grid(column=0,row=2)
# Show main STL section on startup on/off
self.showMainSTLVar = tk.BooleanVar()
self.showMainSTLVar.set(str2bool(self.propertiesDict['showMainSTLSectionExpanded']))
print(self.showMainSTLVar.get())
self.checkBtn2 = tk.Checkbutton(Frame, text='Main STL Section', variable=self.showMainSTLVar)
self.checkBtn2.grid(column=0,row=3)
main.py
from settingsEditor import mySettingsEditor
...
settEditor = mySettingsEditor()
This is how it looks in the GUI when executed separately (terminal with print output to the left):
Thats the result when I add it in main.py. The boxes are unchecked, but .get() tells me the values are correctly assigned to the tk variables.
As suggested by jasonharper, switching to Toplevel() for the child windows fixed the issue. Thanks alot!

Python: why must Tkinter class instantiation use a Frame?

If I want to create a Tkinter GUI simply with statements, I can do this:
from Tkinter import *
root = Tk()
root.title("Test Window")
tkFrame = Frame(root)
tkButton = Button(tkFrame)
[...]
The documentation, however, advises that Tkinter be used with a class definition, subclassing a Frame widget:
class App(Frame):
[...]
I would like to understand why that is so. Why can't we subclass the Frame's container, the window? It appears that is what is done with statements in the first example, so why not in a class definition?
EDIT (following Bryan Oakley's answer):
I would like to instantiate at the highest level of Tkinter, which I assume to be Tk() (though I have come across references stating Frame is the top level, but never mind). Indeed, the following will create a window:
from Tkinter import *
class Application(Tk):
pass
app = Application()
app.mainloop()
...but as soon as I try to add widgets I either get errors or two windows, with the widgets in a new window, depending on how I structure the code. Here's a basic example that will produce a second window with the button:
from Tkinter import *
class Application(Tk):
tkBtn = Button()
tkBtn.pack()
app = Application()
app.mainloop()
Anything more, using self, __init__, etc., produces errors. Could someone point me to working code that instantiates Tkinter at the highest level? Just like all the Frame subclasses I'm seeing, but at the highest level?
There is nothing that says a tkinter class must inherit from a frame. You can inherit from any of the tkinter widgets, or any other classs. If you have found documentation that states otherwise, that documentation is wrong. Using Frame is a logical choice since it is designed to be a container of other widgets, but it is not the only choice.
Personally I inherit from a frame because I find it convenient. Some of my GUIs need the ability to open more than one identical window. By having my main code in a Frame I am able to create multiple windows simply by creating multiple instances of the frame, and packing them in Toplevel widgets.
When you inherit from Tk, you can only have a single instance. In the real world that's usually enough, and there's absolutely nothing wrong with doing it that way. Since I personally write a fair number of tkinter programs, having them all start out exactly the same is convenient for me.
Another good choice is a Canvas since you can easily add a background image, which is not something you can do with a Frame.
Bottom line: you are absolutely not required to inherit from Frame. Inherit from whatever you want.
(the following was written in response to an edit of the original question)
In reference to this code:
from Tkinter import *
class Application(Tk):
tkBtn = Button()
tkBtn.pack()
app = Application()
app.mainloop()
The reason you see two windows is that you're not creating the class properly. You need to call the __init__ method of the superclass before creating widgets, because that's what actually creates the root window. Because you don't, you end up with two windows. You get one that is created implicitly when you add a button to a not-yet-constructed root window, and you get another when your subclass finishes initializing.
The solution is to not take shortcuts, and instead initialize the class properly:
from Tkinter import *
class Application(Tk):
def __init__(self):
Tk.__init__(self)
tkBtn = Button()
tkBtn.pack()
app = Application()
app.mainloop()
Note that this isn't a tkinter-specific problem. When subclassing, unless you have explicit reasons to do otherwise, you always should call the __init__ method of the superclass.
You asked for working examples, here are a couple:
https://stackoverflow.com/a/22424245/7432
https://stackoverflow.com/a/11405393/7432
You might also want to read the responses in the question Inheriting from Frame or not in a Tkinter application

cget('image') method returning pyimage1 instead of the image name

I'm new to programming and I'm attempting to create an application using tkinter from python 3.3. In this application I'm using buttons containing images and I want to perform actions that depend on the kind of image that the buttons are containing. This is a simplified version of my program:
from tkinter import *
master=Tk()
c_black = PhotoImage(file="c_black.gif")
b=Button(master, image=c_black)
print(b.cget('image'))
master.mainloop()
Instead of
c_black
the console returns
pyimage1
And I have no idea why. I've been trying to figure it out for hours now. Perhaps there's a way to do it differently?
With cget() you can only retrieve the property as a string, so you need to store the reference to the PhotoImage object:
b = Button(...)
b.image = c_black
print(b.image.cget('file'))

AttributeError: Message instance has no attribute 'pack'

I'm using Tkinter for the GUI, and I have one problem:
I try to make a message widget, and when I write:
body = Message(top, bd = 2)
body.pack(side=RIGHT)
I get this error:
body.pack(side=RIGHT)
AttributeError: Message instance has no attribute 'pack'
I dont understand this becaue I checked in some guides and Its allowed to use 'message' this way, as seen here in the example: http://www.tutorialspoint.com/python/tk_message.htm
Is there another way to write this?
There are at least two Message classes in Tkinter. One of them comes from tkMessageBox.Message, and the other one is from Tkinter.Message. The former is a subclass of the Dialog from tkCommonDialog, and since packing a dialog is meaningless, there is no pack method for this case. The later is a Tk widget called message, which is the one you want; being a widget, it makes sense to pack it.
Your complete code mostly like have something in the form (Python 2):
from Tkinter import *
from tkMessageBox import *
The second import shadows the Message class from the first import. To use the Message class you are after, simply change the above code to:
from Tkinter import *
import tkMessageBox
Then adapt your code accordingly.

Python Tkinter - global name Tk() is not defined

I've been following a tutorial for the tkinter interface in python and it uses the following piece of code to declare a root widget for the program which then has children widgets:
root = Tk()
I'm getting the following error when trying to interpret this piece of code:
Global name Tk() is not defined
I'm fairly sure this is because tkinter has changed since the tutorial; I cannot find any other tutorials that do not use snippets of code like this so they wouldn't work either.
The question I have is in context simple, but searching, I cannot find the answer;
How can I bypass this: what has changed to the syntax of tkinter and what is the new method of sorts to declare a root widget? additionally it would be brilliant if anybody has the knowledge of tkinter to warn me whether the way in which you can add children widgets to the root has changed as well.
Thank you for any and all replies ~ Michael
You probably forgot from Tkinter import * at the top.
Alternatively, there's
import Tkinter
or
import Tkinter as tk
Edit: Generally, you want to use the idiom from <library> import <module>, so for your specific example from Tkinter import Tk would work.
which just allows you type tk.Button, for example, rather than Tkinter.Button throughout your code. And if you're using Python 3.x, the library is lowercase.
import tkinter
For general importing questions, I've seen the Importing Python Modules link referenced a lot on SO.
You seem to have named the file tkinter.py. You cannot name a file with the module you are importing. Python will try to import from your existing file instead of tkinter module. There will be module name collison. Try to rename your file name.
from Tkinter import *
root = Tk()

Categories