So I'm making an rss reader using the tkinter library, and in one of my methods I create a text widget. It displays fine until I try to add scrollbars to it.
Here is my code before the scrollbars:
def create_text(self, root):
self.textbox = Text(root, height = 10, width = 79, wrap = 'word')
self.textbox.grid(column = 0, row = 0)
Here is my code after:
def create_text(self, root):
self.textbox = Text(root, height = 10, width = 79, wrap = 'word')
vertscroll = ttk.Scrollbar(root)
vertscroll.config(command=self.textbox.yview)
vertscroll.pack(side="right", fill="y", expand=False)
self.textbox.config(yscrllcommand=vertscroll.set)
self.textbox.pack(side="left", fill="both", expand=True)
self.textbox.grid(column = 0, row = 0)
This gives me the error
_tkinter.TclError: cannot use geometry manager pack inside .56155888 which already has slaves managed by grid on the line
vertscroll.pack(side="right", fill="y", expand=False)
Any ideas how to fix this?
Per the docs, don't mix pack and grid in the same master window:
Warning: Never mix grid and pack in the same master window. Tkinter
will happily spend the rest of your lifetime trying to negotiate a
solution that both managers are happy with. Instead of waiting, kill
the application, and take another look at your code. A common mistake
is to use the wrong parent for some of the widgets.
Thus, if you call grid on the textbox, do not call pack on the scrollbar.
import Tkinter as tk
import ttk
class App(object):
def __init__(self, master, **kwargs):
self.master = master
self.create_text()
def create_text(self):
self.textbox = tk.Text(self.master, height = 10, width = 79, wrap = 'word')
vertscroll = ttk.Scrollbar(self.master)
vertscroll.config(command=self.textbox.yview)
self.textbox.config(yscrollcommand=vertscroll.set)
self.textbox.grid(column=0, row=0)
vertscroll.grid(column=1, row=0, sticky='NS')
root = tk.Tk()
app = App(root)
root.mainloop()
The reason of the code is simple, you CANNOT use pack and grid inside the same class or for the same frame. Thus, use only one.
You can't use pack and grid inside the same class or the same frame.use only one
Related
Creates two windows and gridding is not correct. Some additional comments in the code initiation.
I have used this approach, without the super init with no problem, many times.
Advice appreciated.
Thanks
# timhockswender#gmail.com
import tkinter as tk
from tkinter import ttk
class constants_page(tk.Frame):
def __init__(self):
super(constants_page, self).__init__() # from stackoverflow
# if not used error = 'constants_page' object has no attribute 'tk'
# if used, another tiny window is opened
# in addtion to the constants_page
self.constants_page = tk.Tk()
self.constants_page.geometry("1000x500") #width*Length
self.constants_page.title("Owen's Unit Conversion App")
self.constants_page.configure(background='light blue')
self.CreateWidgets()
def CreateWidgets(self):
self.value_label = ttk.Label(self.constants_page,text="Value----->" , width =10 )
self.value_label.grid(row=0, column=1, columnspan=1, sticky='nse')
# Problem: not gridding properly
self.title_label = ttk.Label(self.constants_page, text="Important Physical Constants",
anchor=tk.CENTER, font=("Arial",20)).grid(row=2, columnspan=2)
for r in range(2):
self.constants_page.rowconfigure(r, weight=1, uniform='row')
for c in range(2):
self.constants_page.columnconfigure(c, weight=1 )
def Show_Page():
# Create the entire GUI program
program = constants_page()
program.mainloop()
if __name__ == "__main__":
Show_Page()
The super call expects you to provide a root window (an instance of tk.Tk()). If you don't provide one it defaults to the first root window opened, and if none has been opened yet then it helpfully opens one for you. A few lines later you open a second one yourself.
The easy fix is to remove the self.constants_page = tk.Tk() line. The proper fix is to make the Tk() instance outside of the class and pass it in. This allows you to use the Frame class itself to lay out widgets (use self instead of self.constants_page). Try this:
import tkinter as tk
from tkinter import ttk
class constants_page(tk.Frame):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
master.geometry("1000x500") #width*Length
master.title("Owen's Unit Conversion App")
self.configure(background='light blue')
self.CreateWidgets()
def CreateWidgets(self):
self.value_label = ttk.Label(self,text="Value----->" , width =10 )
self.value_label.grid(row=0, column=1, columnspan=1, sticky='nse')
self.title_label = ttk.Label(self, text="Important Physical Constants",
anchor=tk.CENTER, font=("Arial",20)).grid(row=2, columnspan=2)
for r in range(2):
self.rowconfigure(r, weight=1, uniform='row')
for c in range(2):
self.columnconfigure(c, weight=1 )
def Show_Page():
# Create the entire GUI program
program = tk.Tk()
win = constants_page(program)
win.pack()
program.mainloop()
if __name__ == "__main__":
Show_Page()
I am aware that you cannot use different types of geometry managers within the same Tkinter window, such as .grid() and .pack(). I have a window that has been laid out using .grid() and I am now trying to add a status bar that would be snapped to the bottom of the window. The only method I have found online for this is to use .pack(side = BOTTOM), which will not work since the rest of the window uses .grid().
Is there a way that I can select the bottom of the window to place widgets from when using .grid()?
from tkinter import *
from tkinter.ttk import *
import tkinter as tk
class sample(Frame):
def __init__(self,master=None):
Frame.__init__(self, master)
self.status = StringVar()
self.status.set("Initializing")
statusbar = Label(root,textvariable = self.status,relief = SUNKEN, anchor = W)
statusbar.pack(side = BOTTOM, fill = X)
self.parent1 = Frame()
self.parent1.pack(side = TOP)
self.createwidgets()
def createwidgets(self):
Label(self.parent1,text = "Grid 1,1").grid(row = 1, column = 1)
Label(self.parent1,text = "Grid 1,2").grid(row = 1, column = 2)
Label(self.parent1,text = "Grid 2,1").grid(row = 2, column = 1)
Label(self.parent1,text = "Grid 2,2").grid(row = 2, column = 2)
if __name__ == '__main__':
root = Tk()
app = sample(master=root)
app.mainloop()
So using labels since I was kinda lazy to do other stuff, you can do frames to ensure that each section of your window can be packed/grid as required. Frames will be a useful tool for you to use when trying to arrange your widgets. Note that using a class can make things a little easier when deciding your parents. So imagine each frame is a parent and their children can be packed as required. So I would recommend drawing out your desired GUI and see how you will arrange them. Also if you want to add another frame within a frame simply do:
self.level2 = Frame(self.parent1)
You can check out additional settings in the docs
http://effbot.org/tkinterbook/frame.htm
PS: I am using a class hence the self, if you don't want to use classes then its okay to just change it to be without a class. Classes make it nicer to read though
Just give it a row argument that is larger than any other row. Then, give a weight to at least one of the rows before it.
Even better is to use frames to organize your code. Pack the scrollbar on the bottom and a frame above it. Then, use grid for everything inside the frame.
Example:
# layout of the root window
main = tk.Frame(root)
statusbar = tk.Label(root, text="this is the statusbar", anchor="w")
statusbar.pack(side="bottom", fill="x")
main.pack(side="top", fill="both", expand=True)
# layout of the main window
for row in range(1, 10):
label = tk.Label(main, text=f"R{row}")
label.grid(row=row, sticky="nsew")
main.grid_rowconfigure(row, weight=1)
...
So I'm making an rss reader using the tkinter library, and in one of my methods I create a text widget. It displays fine until I try to add scrollbars to it.
Here is my code before the scrollbars:
def create_text(self, root):
self.textbox = Text(root, height = 10, width = 79, wrap = 'word')
self.textbox.grid(column = 0, row = 0)
Here is my code after:
def create_text(self, root):
self.textbox = Text(root, height = 10, width = 79, wrap = 'word')
vertscroll = ttk.Scrollbar(root)
vertscroll.config(command=self.textbox.yview)
vertscroll.pack(side="right", fill="y", expand=False)
self.textbox.config(yscrllcommand=vertscroll.set)
self.textbox.pack(side="left", fill="both", expand=True)
self.textbox.grid(column = 0, row = 0)
This gives me the error
_tkinter.TclError: cannot use geometry manager pack inside .56155888 which already has slaves managed by grid on the line
vertscroll.pack(side="right", fill="y", expand=False)
Any ideas how to fix this?
Per the docs, don't mix pack and grid in the same master window:
Warning: Never mix grid and pack in the same master window. Tkinter
will happily spend the rest of your lifetime trying to negotiate a
solution that both managers are happy with. Instead of waiting, kill
the application, and take another look at your code. A common mistake
is to use the wrong parent for some of the widgets.
Thus, if you call grid on the textbox, do not call pack on the scrollbar.
import Tkinter as tk
import ttk
class App(object):
def __init__(self, master, **kwargs):
self.master = master
self.create_text()
def create_text(self):
self.textbox = tk.Text(self.master, height = 10, width = 79, wrap = 'word')
vertscroll = ttk.Scrollbar(self.master)
vertscroll.config(command=self.textbox.yview)
self.textbox.config(yscrollcommand=vertscroll.set)
self.textbox.grid(column=0, row=0)
vertscroll.grid(column=1, row=0, sticky='NS')
root = tk.Tk()
app = App(root)
root.mainloop()
The reason of the code is simple, you CANNOT use pack and grid inside the same class or for the same frame. Thus, use only one.
You can't use pack and grid inside the same class or the same frame.use only one
I am using the ttk.Progressbar in my app. I have scoured the net for an answer but no avail.
I have the following code which is working well. But I want to change the thickness of the bar.
progressbar = ttk.Progressbar(myGui, orient=HORIZONTAL,
length=400, mode="determinate",
variable=value_progress,
)
progressbar.pack()
I want the length to still be 400, but from the top of the bar to the bottom, I wish to decrease that so its half or less then half. (I want my bar on a diet, so to say)
But I am beating my head against the wall to figure out a solution.
Andy ideas? Thanks in advance.
The ttk progress bar appears to lack the width option in Python.
Using a work around (here) for an issue with a Tkinter Button. From this I have been able to create a working solution.
The key to solving the issue was to add the progress bar to a window inside the canvas. Using a window inside the canvas doesn't cause the canvas to resize when the widget is added which means we can control the width of the progress bar.
I have created some working example code:
from ttk import Progressbar
import Tkinter
class Example(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
value_progress =50
self.parent.title("Progressbar Thingymawhatsit")
self.config(bg = '#F0F0F0')
self.pack(fill = Tkinter.BOTH, expand = 1)
#create canvas
canvas = Tkinter.Canvas(self, relief = Tkinter.FLAT, background = "#D2D2D2",
width = 400, height = 5)
progressbar = Progressbar(canvas, orient=Tkinter.HORIZONTAL,
length=400, mode="indeterminate",
variable=value_progress,
)
# The first 2 create window argvs control where the progress bar is placed
canvas.create_window(1, 1, anchor=Tkinter.NW, window=progressbar)
canvas.grid()
def main():
root = Tkinter.Tk()
root.geometry('500x50+10+50')
app = Example(root)
app.mainloop()
if __name__ == '__main__':
main()
So to sum up the progress bar is the same size but you just cant see half of it!
If you must use the xpnative theme or themes like it, then you will likely not have the option to change the thickness the conventional way. However if you use the default theme, you can configure the thickness with a style. There are likely other themes that let you do this as well, and if you're going to be playing around a lot with the look and feel of your program, you may wish to use these instead.
from Tkinter import *
from ttk import *
def main():
root = Tk()
s = Style()
s.theme_use("default")
s.configure("TProgressbar", thickness=50)
pb = Progressbar(root, style="TProgressbar")
pb.pack()
root.mainloop()
main()
You can just use the ipady option of pack manager.
progressbar = ttk.Progressbar(myGui, orient=HORIZONTAL,
length=400, mode="determinate",
variable=value_progress,
)
progressbar.pack(ipady=10)
I'm making some pretty pictures using a tkinter canvas and overlaying text on top of circles like in the following picture:
http://static.guim.co.uk/sys-images/Guardian/Pix/pictures/2012/11/6/1352220546059/Causes-of-deaths-graphic-008.jpg
I want the font size to be dependent on the same number that the circle size is dependent on.
tempfont = tkFont.Font(family='Helvetica',size=int(round(ms*topnode[1])))
self.display.create_text(center[0],center[1],fill = "#FFFFFF",text = int(round(ms*topnode[1])),font = tempfont)
My problem is that when I use the above code, the overlayed text is a constant size for every text object. The text itself is right, as in it displays the number that I want the font size to be, just not in the correct font size. I've experimented with putting in constant integers in the size definition (works as it's supposed to), and adding a del(tempfont) immediately after the above 2 lines of code, but I haven't found what fixes this problem yet.
What am I doing wrong?
Here's a self-contained little program that reproduces the problem:
from Tkinter import *
import tkFont
class TestApp(Frame):
def __init__(self, master=None, height = 160, width = 400):
Frame.__init__(self, master)
self.grid()
self.createWidgets()
def createWidgets(self):
self.display = Canvas(self, width = 800, height = 320, bg = "#FFFFFF")
self.display.grid(row=0,column=0)
def recurtext(tsize):
if tsize > 20:
recurtext(tsize-10)
tempfont = tkFont.Font(family='Helvetica',size=tsize)
self.display.create_text(800 - (tsize*12),160, text = str(tsize), font = tempfont)
recurtext(60)
app = TestApp()
app.master.title("Test")
app.mainloop()
The gist is that recurtext resizes the font recursively, and shows writes out the font size in that size... or I think it should. Maybe this is a bug with tkinter, but I'm still holding on to some hope that I'm the one who made a mistake in the logic here.
I've never run across this behavior before; it looks like a Tkinter bug. The good news is, there appears to be a workaround. If you give each font a unique name the problem seems to vanish.
The following example shows multiple lines, each with a different font size:
import Tkinter as tk
import tkFont
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.display = tk.Canvas(self, width=400, height=600, background="black")
self.display.pack(side="top", fill="both", expand=True)
y = 10
for size in range (2, 38, 2):
tempfont = tkFont.Font(family='Helvetica',size=size,
name="font%s" % size)
self.display.create_text(10, y, fill = "#FFFFFF",text = size,
font = tempfont, anchor="nw")
y = y + tempfont.metrics()["linespace"]
if __name__ == "__main__":
root = tk.Tk()
frame = Example(parent=root)
frame.pack(side="top", fill="both", expand=True)
root.mainloop()