I am trying to learn Python and trying something GUI in Python and came across this Tkinter module. My code runs but the window does not appear when I run. My code is as follows:
from Tkinter import *
#to create a root window
root = Tk()
The program runs, gives no errors but the window does not show up.
Add this to your code root.mainloop(), Here's a tutorial.
In response to your comment
#Also note that `from <module> import *` is generally frowned upon
#since it can lead to namespace collisions. It's much better to only
#explicitly import the things you need.
from Tkinter import Tk, Label
root = Tk()
w = Label(root, text="Hello, world!")
w.pack()
root.mainloop()
As other answers have pointed out, you need to call mainloop on the root object.
I recommend an OO-style of programming, and I also recommend not doing a global import (ie: not 'from Tkinter import *').
Here's a template I usually start out with:
import Tkinter as tk
class ExampleView(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
l = tk.Label(self, text="your widgets go here...", anchor="c")
l.pack(side="top", fill="both", expand=True)
if __name__=='__main__':
root = tk.Tk()
view = ExampleView(root)
view.pack(side="top", fill="both", expand=True)
root.mainloop()
This makes it easy to keep your main logic at the start of the file, and keep the creation of the root and the calling of mainloop together, which I think makes the code a little bit easier to understand. It also makes reusing this code a little easier (ie: you could create a larger program where this is one of several windows that can be created)
Add root.mainloop() at the end.
Related
I have some general questions regarding working code below:
tkinter is library for graphic interface as I understand I can use it interchangeably with for example Kivy?
Would it be better to learn Kivy instead or other?
Lines import tkinter as tk and from tkinter import * do exactly the same, in the first one I have alias though?
In the code below, why do I have to use ttk in ttk.Progressbar?
I imported whole library with import tkinter as tk so why do i have to reimport ttk just for progress bar? (otherwise it is not working). I would expect to work sth. like tk.Progressbar
In the line btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress), why method "fnUpdateProgress" can't have any variables? Whenever I add any, the button stop working? -> for example btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress(24)) (ofc then some changes in def of the method itself)
I created progress bar (pb) as attribute of the class Test, but wolud it be better to define it as regular variable (without self)? To be honest, code works exactly the same.
Code:
import tkinter as tk
from tkinter import *
from tkinter import ttk
from CreateProgramMain import main
import GlobalVariables
class Test():
####################################################################################
def __init__(self):
self.Progress=0
self.root = tk.Tk()
self.root.title(GlobalVariables.strAppName)
self.root.geometry('400x200')
lbl = Label(self.root, text="Please choose environment.",font=("Arial Bold", 12))
lbl.grid(column=2, row=0,sticky='e')
def btnTestClicked():
main("TEST",self)
btnTest=tk.Button(self.root, text="Test Environment", command=btnTestClicked)
btnTest.grid(column=2, row=15)
#Place progress bar
pb = ttk.Progressbar(self.root,orient='horizontal',mode='determinate',length=200)
pb.grid(column=1, row=65, columnspan=2, padx=10, pady=20)
pb["value"]=self.Progress
pb["maximum"]=100
btnProg = tk.Button(self.root, text = 'update', command=self.fnUpdateProgress)
btnProg.grid(column=2, row=75)
self.root.mainloop()
def fnUpdateProgress(self): #why i cant insert variable inside?
pb["value"]=self.Progress
self.Progress=self.Progress+5
pb.update()
app = Test()
Thank you
it is upto you. However, tkinter and kivy both have their own syntaxes, commands, and their own usages. It might be a little difficult to convert tkinter code to kivy.
it is upto you
Yes. In the first, you have imported tkinter as tk. In the second one. You have done a wild card import. You have imported everything
Tkinter is a folder containing various modules. It contains a file called ttk.py which you have to import to access ttk.
All other classes like Label, Entry, Tk is present in __init__.py
you have to use lambda for it. If you call the function, it will be executed wlright away and the returned value is kept as the command.
Doing command=self.fnUpdateProgress(24)) will execute the function right away. Then, the returned value is kept as a command. Here, it returns None. So the command is nothing or the button is useless.
Use a lambda expression command=lambda: self.fnUpdateProgress(24))
if you don't add self it will be local to the function only. To access ot outside, it would have to be declared global, which is the point to avoid while using classes
I'm working with Tkinter in Python 2.7 on Windows 7, and found the need to create a popup box with a tree-style list of checkboxes. I could not find this in Tkinter, or ttk. I did, however, find it in Tix in the CheckList widget. I got a working standalone example using Tix, but I cannot figure out how to add my Tix.CheckList to my ttk.Frame that controls my main program.
Surely I am not forced to use Tix framework from the ground up?
import Tix
import pandas as pd
import Tkinter as tk
class TreeCheckList(object):
def __init__(self, root):
self.root = root
self.cl = Tix.CheckList(self.root)
self.cl.pack(fill=Tix.BOTH, expand=Tix.YES)
self.cl.hlist.config(bg='white', bd=0, selectmode='none', selectbackground='white', selectforeground='black', drawbranch=True, pady=5)
self.cl.hlist.add('ALL', text='All Messages')
self.cl.hlist.add('ALL.First', text='First')
self.cl.setstatus('ALL.First', "off")
self.cl.hlist.add('ALL.Second', text='Second')
self.cl.setstatus('ALL.Second', "off")
self.cl.autosetmode()
def main():
root = Tix.Tk()
top = Tix.Toplevel(root)
checklist = TreeCheckList(top)
root.update()
top.tkraise()
root.mainloop()
if __name__ == '__main__':
main()
The above code works in a standalone program using all Tix widgets. However, when I try to implement this into my larger program, I receive a TclError: invalid command name "tixCheckList"
To simulate this in the standalone, I changed the lines:
root = Tix.Tk()
top = Tix.Toplevel(root)
to
root = tk.Tk()
top = tk.Toplevel(root)
I was hoping I could just implement a Tix.Toplevel, placing it on a tk.Tk() root, but same issue.
Am I only allowed to use Tix frames when using a Tix widget, or am I misunderstanding something? If anyone has good Tix documentation, I would LOVE whatever I can get. It seems good docs on it are few and far between. Or is this same functionality included in ttk and I've just overlooked it? It seems to be one of the only things left out.
I have just learned that apparently only root needs to be a Tix class. Since Tk, and therefore ttk, classes appear to be added to the Tix root just fine (since most of them extend the Tkinter classes anyway), this appears to be a "fix". So my problem may have been solved by changing just
root = tk.Tk()
to
root = Tix.Tk()
This did require that I pull Tix into a part of my program I wasn't wanting for encapsulation purposes, but I guess there's no other way.
I have made a Toplevel widget but when it pops up it always appears below my root window. Is there an easy way I can make it come to the top most level when it pops up?
you can use the .lift() method on a Toplevel widget:
import tkinter
root = tkinter.Tk()
root.title("root")
top = tkinter.Toplevel(root)
top.title("top")
top.lift(root)
root.mainloop()
according to this documentation you should be able to just use top.lift() to raise above all other windows but it didn't seem to work for me.
Edit: calling top.lift() without arguments does work when called during the mainloop, although since this question was specifically when starting the program that isn't very useful.
try attributes
import tkinter
root = tkinter.Tk()
root.title("root")
top = tkinter.Toplevel(root)
top.attributes('-topmost', 'true')
top.title("top")
root.mainloop()
I'm in the middle of rewriting the code for my first tkinter application, in which I'd avoided using classes. That was a dead end and I have to finally learn class programming in python. I've encountered a very weird error and I have no idea how to fix it. I've tried, but to no effect. What I'm trying to do is specify a font for two labels in my app. It worked well in my previous, class-free code but now it gives me an error:
(...) line 56, in create_widgets
TimeFont = font.Font(family='Palatino', size=88, weight='bold')
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/font.py", line 71, in __init__
root = tkinter._default_root
AttributeError: 'module' object has no attribute '_default_root'
Here's the function I'm using for creating widgets:
def create_widgets(self):
self.set_timer = ttk.Entry(self, textvariable=self.timer)
self.start = ttk.Button(self, text='Start', command=self.start)
TimeFont = font.Font(family='Palatino', size=88, weight='bold') #the infamous line 56
self.display1 = ttk.Label(self, textvariable=self.player1, font=TimeFont)
self.display2 = ttk.Label(self, textvariable=self.player2, font=TimeFont)
And some more code "from above" in case its relevant:
from decimal import *
from tkinter import *
from tkinter import ttk
from tkinter import font
import time, _thread, subprocess
class Chclock(ttk.Frame):
#classmethod
def main(cls):
NoDefaultRoot()
root = Tk()
app = cls(root)
app.grid(sticky=NSEW)
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.resizable(True, False)
root.mainloop()
def __init__(self, root):
super().__init__(root)
root.bind('q', self.player1move)
root.bind('p', self.player2move)
root.bind('b', self.pause)
root.bind('a', self.undo)
root.bind('l', self.undo)
self.create_variables()
self.create_widgets() #here I call the function containing the error
self.grid_widgets()
self.grid_columnconfigure(0, weight=1)
It's probably something silly but I just can't understand what's causing this problem. It used to work fine...
Thanks!
Perhaps the code "NoDefaultRoot()" and the error message "object has no attribute '_default_root'" might have something to do with each other? Notice a correlation? First rule of debugging is to assume the error message is telling you something useful.
The problem is that you are creating a font object without telling that object what window it belongs to. Since you aren't telling it, it chooses to use the default root window. However, you've explicitly requested no default root window.
This is a somewhat strange way to structure your Tkinter program. I recommend reading the answers in the question Python Tkinter Program Structure
Well I've managed to find it. Since some kind person gave this question an upvote I'll post the solution: I've deleted the NoDefaultRoot() line. I'm not sure why it didn't work, and why it works now, but it does... Can someone explain what's happened in the comments? I'm really new to this stuff and the line I'd deleted came with a template.
Sorry if I made a mess.
Having played around a little with both Tkinter and wxPython, I like Tkinter much better in terms of how clean my source code looks. However, it doesn't seem to have as many features; in particular it doesn't have tabs (as in, the tabs at the top of a Firefox window).
A little Googling on the subject offers a few suggestions. There's a cookbook entry with a class allowing you to use tabs, but it's very primitive. There's also Python megawidgets on SourceForge, although this seems very old and gave me errors during installation.
Does anyone have experience making tabbed GUIs in Tkinter? What did you use? Or is it simply the case that anyone who needs more powerful windowing components has to use wxPython?
On recent Python (> 2.7) versions, you can use the ttk module, which provides access to the Tk themed widget set, which has been introduced in Tk 8.5.
Here's how you import ttk in Python 2:
import ttk
help(ttk.Notebook)
In Python 3, the ttk module comes with the standard distributions as a submodule of tkinter.
Here's a simple working example based on an example from the TkDocs website:
from tkinter import ttk
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
def demo():
root = tk.Tk()
root.title("ttk.Notebook")
nb = ttk.Notebook(root)
# adding Frames as pages for the ttk.Notebook
# first page, which would get widgets gridded into it
page1 = ttk.Frame(nb)
# second page
page2 = ttk.Frame(nb)
text = ScrolledText(page2)
text.pack(expand=1, fill="both")
nb.add(page1, text='One')
nb.add(page2, text='Two')
nb.pack(expand=1, fill="both")
root.mainloop()
if __name__ == "__main__":
demo()
Another alternative is to use the NoteBook widget from the tkinter.tix library. To use tkinter.tix, you must have the Tix widgets installed, usually alongside your installation of the Tk widgets. To test your installation, try the following:
from tkinter import tix
root = tix.Tk()
root.tk.eval('package require Tix')
For more info, check out this webpage on the PSF website.
Note that tix is pretty old and not well-supported, so your best choice might be to go for ttk.Notebook.
If anyone still looking, I have got this working as Tab in tkinter. Play around with the code to make it function the way you want (for example, you can add button to add a new tab):
from tkinter import *
class Tabs(Frame):
"""Tabs for testgen output"""
def __init__(self, parent):
super(Tabs, self).__init__()
self.parent = parent
self.columnconfigure(10, weight=1)
self.rowconfigure(3, weight=1)
self.curtab = None
self.tabs = {}
self.addTab()
self.pack(fill=BOTH, expand=1, padx=5, pady=5)
def addTab(self):
tabslen = len(self.tabs)
if tabslen < 10:
tab = {}
btn = Button(self, text="Tab "+str(tabslen), command=lambda: self.raiseTab(tabslen))
btn.grid(row=0, column=tabslen, sticky=W+E)
textbox = Text(self.parent)
textbox.grid(row=1, column=0, columnspan=10, rowspan=2, sticky=W+E+N+S, in_=self)
# Y axis scroll bar
scrollby = Scrollbar(self, command=textbox.yview)
scrollby.grid(row=7, column=5, rowspan=2, columnspan=1, sticky=N+S+E)
textbox['yscrollcommand'] = scrollby.set
tab['id']=tabslen
tab['btn']=btn
tab['txtbx']=textbox
self.tabs[tabslen] = tab
self.raiseTab(tabslen)
def raiseTab(self, tabid):
print(tabid)
print("curtab"+str(self.curtab))
if self.curtab!= None and self.curtab != tabid and len(self.tabs)>1:
self.tabs[tabid]['txtbx'].lift(self)
self.tabs[self.curtab]['txtbx'].lower(self)
self.curtab = tabid
def main():
root = Tk()
root.geometry("600x450+300+300")
t = Tabs(root)
t.addTab()
root.mainloop()
if __name__ == '__main__':
main()
While it may not help you at the moment, tk 8.5 comes with an extended set of widgets. This extended set is available with tk 8.4 by way of an extension known as "tile". Included in the extended set of widgets is a notebook widget. Unfortunately, at this time Tkinter by default uses a fairly old version of Tk that doesn't come with these widgets.
There have been efforts to make tile available to Tkinter. Check out http://tkinter.unpythonic.net/wiki/TileWrapper. For another similar effort see http://pypi.python.org/pypi/pyttk. Also, for a taste of how these widgets look (in Ruby, Perl and Tcl) see http://www.tkdocs.com/.
Tk 8.5 is a huge improvement over stock Tk. It introduces several new widgets, native widgets, and a theming engine. Hopefully it will be available by default in Tkinter some day soon. Too bad the Python world is lagging behind other languages.
update: The latest versions of Python now include support for the themed widgets out of the box. _
"Or is it simply the case that anyone who needs more powerful windowing components has to use wxPython?"
Short answer: yes.
Long answer:
It may take some practice for your wxPython code to feel "clean," but it is nicer and much more powerful than Tkinter. You will also get better support, since more people use it these days.
What problems did you have with pmw? It's old, yes, but it's pure python so it should work.
Note that Tix doesn't work with py2exe, if that is an issue for you.