Frame loosing height when filled tkinter - python

Hello everyone i am learning to make a gui with tkinter but i run into something and can't find the answer to it i have 3 frames a header a shadow for the header and a main content frame and that works fine
code :
root = Tk()
root.geometry("1080x600")
root.minsize(width=1080, height=600)
root.maxsize(width=1080, height=600)
root.title("learning ui")
headerFrame = Frame(root, height=50, bg="#17181b")
headerShadow = Frame(root, height=3, bg="#08090a")
contentFrame = Frame(root, bg="#17181b")
headerFrame.pack(side=TOP, fill=X)
headerShadow.pack(fill=X)
contentFrame.pack(fill=BOTH, expand=True)
root.mainloop()
Screen shot :
But when i pack something to the header it looses its height.
code:
root = Tk()
root.geometry("1080x600")
root.minsize(width=1080, height=600)
root.maxsize(width=1080, height=600)
root.title("learning ui")
headerFrame = Frame(root, height=50, bg="#17181b")
headerShadow = Frame(root, height=3, bg="#08090a")
contentFrame = Frame(root, bg="#17181b")
headerFrame.pack(side=TOP, fill=X)
headerShadow.pack(fill=X)
contentFrame.pack(fill=BOTH, expand=True)
main.e = Entry(headerFrame)
main.e.pack(side=RIGHT)
main.e.focus_set()
searchBtn = Button(headerFrame, text="Search", command=lambda: callback(retrieve_input()))
searchBtn.pack(side=RIGHT)
def callback(q):
print q
root.mainloop()
Screen shot:

All widgets are designed to "shrink to fit" their children. While this may seem counter-intuitive at first, it's the best way to do widget layout. Don't try to force a frame or window to be a specific size, just put the widgets in that you want and it will end up being the right size.
If you want to turn this feature off you can, but I strongly recommend against it. If you want to know more, search for "overrideredirect".

Related

Python Calculator results are not being displayed

so i was trying to make a python calculator, that opens like a window, but before the calculations i was trying to make it display the numbers that i clicked, everything was normal, the append, the list, everything was normal until it had to display the actual numbers, where it displays nothing, i tried to make change the label to "hi" for example to see if the problem is with the list, but nothing is being displayed, can someone help me get numbers to be displayed in the "results" area? here is my code:
root = tk.Tk()
color = '#263D42'
numbers = []
Background = tk.Canvas(root, height=600, width=601, bg=color)
Background.pack()
resultBack = tk.Canvas(root, height=150, width=400, bg="#E4E0E0")
resultBack.place(x=50, y=1)
root.title('Calculator')
root.iconphoto(False, tk.PhotoImage(file='plus.ico'))
root.resizable(width = False, height = False)
root.geometry("500x600")
for number in numbers:
label = tk.Label(root, text="hi", bg="black")
label.pack()
frame = tk.Frame(root, bg="white")
frame.place(relwidth=0.8, relheight=0.8, relx=0.1, rely=0.1) #frame
def addOne():
for widget in frame.winfo_children():
widget.destroy()
numbers.append('1')
for number in numbers:
print(number)
label = tk.Label(root, text=number, bg="black")
label.pack()
print(numbers)
one = tk.Button(root, text="1", padx=10, pady=5, fg="#000000", bg="#ffffff", command=addOne)
one.place(x=30, y=30)
root.mainloop()
You should not be creating and deleting your labels like that; you can just change them.
Maybe try something like this:
import tkinter as tk
root = tk.Tk()
numbers = []
root.title('Calculator')
root.resizable(width = False, height = False)
root.geometry("500x600")
label_text = tk.StringVar()
label_text.set('hi')
label = tk.Label(root, textvariable=label_text)
label.pack()
frame = tk.Frame(root, bg="white")
frame.place(relwidth=0.8, relheight=0.8, relx=0.1, rely=0.1) #frame
def addOne():
numbers.append(1)
work = ""
for i in numbers:
work+=str(i)
label_text.set(work)
one = tk.Button(root,
text="1",
padx=10,
pady=5,
fg="#000000",
bg="#ffffff",
command=addOne)
one.place(x=30, y=30)
root.mainloop()
That should get the numbers showing up. StringVars are your friend for these sorts of things. As you update them, tk automatically updates the widget they are attached to.
From here, you will probably want to move things around to look better etc. and you probably don't want to have to add a method for each button (addTwo, addThree, addFour etc.) Let us know if you need more help.

How do you make a child label smaller than its parent frame?

There is only one frame in my GUI, and it resizes itself to the size of the window. The frame has a child label, and I want the label to always be 1/3 the height of the frame and 1/1.5 the width of the frame. The code below tries to do that but the label always resizes itself to the size of the frame.
import tkinter
tk = tkinter.Tk()
tk.geometry("400x400")
f = tkinter.Frame(tk, bd=5, bg="white")
f.pack(padx=10, pady=10)
def callback(event):
f.config(height=tk.winfo_height(), width=tk.winfo_width())
l.config(width=int(f.winfo_width()/1.5), height=int(f.winfo_height()/3))
l = tkinter.Label(f, text="lead me lord", bg="yellow", relief=tkinter.RAISED, bd=5)
l.pack(side="bottom")
tk.bind("<Configure>", callback)
tk.mainloop()
The width and height of the label are in characters. In order to use pixels, you need to add an empty image to the label:
img = tkinter.PhotoImage() # an image of size 0
l = tkinter.Label(f, text="lead me lord", bg="yellow", relief=tkinter.RAISED, bd=5,
image=img, compound='center')
Actually you don't need to resize the frame in the callback if you add fill="both", expand=1 into f.pack(...):
import tkinter
tk = tkinter.Tk()
tk.geometry("400x400")
f = tkinter.Frame(tk, bd=5, bg="white")
f.pack(padx=10, pady=10, fill="both", expand=1)
def callback(event):
l.config(width=int(f.winfo_width()/1.5), height=int(f.winfo_height()/3))
#l.config(width=event.width*2//3, height=event.height//3) # same as above line if bind on frame
img = tkinter.PhotoImage()
l = tkinter.Label(f, text="lead me lord", bg="yellow", relief=tkinter.RAISED, bd=5,
image=img, compound='center')
l.pack(side="bottom")
f.bind("<Configure>", callback) # bind on frame instead of root window
tk.mainloop()
Given your precise specifications, the best solution is to use place since it lets you use relative widths and heights. However, if you plan to have other widgets in the window, place is rarely the right choice.
This example will do exactly what you asked: place the label at the bottom with 1/3 the height and 1/1.5 the width. There is no need to have a callback for when the window changes size.
Note: I had to change the call to pack for the frame. The text of your question said it would expand to fill the window but the code you had wasn't doing that. I added the fill and expand options.
import tkinter
tk = tkinter.Tk()
tk.geometry("400x400")
f = tkinter.Frame(tk, bd=5, bg="white")
f.pack(padx=10, pady=10, fill="both", expand=True)
l = tkinter.Label(f, text="lead me lord", bg="yellow", relief=tkinter.RAISED, bd=5)
l.place(relx=.5, rely=1.0, anchor="s", relheight=1/3., relwidth=1/1.5)
tkinter.mainloop()

Tkinter's button can't change border color

Here's my Tkinter code:
Photoshop = Tkinter.Button(root,
text = 'Photoshop',
fg = '#37d3ff',
bg = '#001d26',
bd = 10,
highlightthickness=4,
highlightcolor="#37d3ff",
highlightbackground="#37d3ff",
borderwidth=4)
However, after I grid my Button, the color of border doesn't shows up. Instead, it used default grey.
You may place the button inside its own frame like this:
buttonborder = Tkinter.Frame(root,
highlightbackground="#37d3ff",
highlightcolor="#37d3ff",
highlightthickness=4,
bd=0)
photoshop = Tkinter.Button(buttonborder,
text='Photoshop',
fg='#37d3ff',
bg='#001d26')
This works for me:
import Tkinter as tk
root = tk.Tk()
Photoshop = tk.Button(root, text = 'Photoshop',
fg = '#37d3ff',
bg = '#001d26',
bd = 10,
highlightthickness=4,
highlightcolor="#37d3ff",
highlightbackground="#37d3ff",
borderwidth=4)
Photoshop.pack()
root.mainloop()
You can add your widget to a Frame and make the Frame's highlight background to be the color you want for your widget's border. CODE Example:
import tkinter as tk
root = tk.Tk()
buttonborder = tk.Frame(root, highlightbackground="#37d3ff",
highlightthickness=3, bd=0)
photoshop = tk.Button(buttonborder, text='Photoshop', fg='#37d3ff')
photoshop.pack()
buttonborder.pack()
root.mainloop()
You can do it with LabelFrame() and relief.
Works in windows.
from tkinter import *
App = Tk()
Border = LabelFrame(App,
bd=5, #<- Borderwidth.
bg="blue", #<- Border color.
relief=FLAT)
Border.pack(padx=10, pady=10)
Btn1 = Button(Border, #<- in Border Widget.
text="Button",
font="Arial 16 bold",
width=16,
bg="red",
fg="white",
relief=FLAT)
Btn1.pack()
App.mainloop()
There is no perfect way to do this unfortunately, But you sure can hack around and place a tkinter Frame that is just a little bigger than the actual button to set them apart by using the frame as a coloured border, Something like this. Should work on Win and Mac or any other OS's..
(assuming you already know how to work with tkinter root window..)
`borderFrame = Frame(root, bg="red(your desired colour of choice)")
borderFrame.pack(padx=21, pady=21)
button = Button(borderFrame, bg="blue",text="click me", relief='flat')
button.pack(padx=20, pady=20)`

Expand a listbox over 2 columns Tkinter

I have the following interface: 3 frames from which 2 are on the left-hand, frame1 and frame2 and another one which is on the right, frame3.
I want to create another frame, frame4 which will have the label Output and under it there should be a Listbox. I want that both these widgets to span over the previous frames, each being places in a cell by using the grid manager.
Also I am not sure if Listbox is the widget I should be using. I want something which will contain the output of the program I will run through my application. I also thought of Entry but I need something in which I can display more than one line.
This is the code I have so far:
from Tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.grid(row=0,column=0)
frame2 = Frame(root)
frame2.grid(row=1,column=0)
frame3 = Frame(root)
frame3.grid(row=0,column=1)
frame4 = Frame(root)
frame4.grid(row=2,columnspan=2)
l5 = Label(frame4, text='Output:').grid(row=2,columnspan=2)
output = Listbox(frame4, height=5)
#output.grid(row=2,column=0,columnspan=2)
#output.pack(side=LEFT, fill=BOTH, expand=1)
root.mainloop()
I managed to make the label to span across the other frames, but when I uncommented either of the last 2 lines, the interface didn't open and the program just froze.
How can I solve this?
I slightly ammended your code:
from tkinter import * # for python 2.7 use Tkinter
root = Tk()
frame1 = Frame(root, bg='red', height=20)
frame1.grid(row=0,column=0, sticky=W+E)
frame3 = Frame(root, bg='blue', height=20)
frame3.grid(row=0,column=1, sticky=W+E)
frame2 = Frame(root, bg='green', height=20)
frame2.grid(row=1,column=0, sticky=W+E)
frame4 = Frame(root)
frame4.grid(row=2,columnspan=2, sticky=E+W)
l5 = Label(frame4, text='Output:', bg='orange').grid(row=0, column=0, sticky=E+W)
output = Listbox(frame4, height=5, width=50)
output.grid(row=1,column=0)
#output.pack(side=LEFT, fill=BOTH, expand=1)
root.mainloop()
This results in:
So basically what I did was to add bg, height and sticky parameters to frames and label to easily visual what is happening and how they frames are laid out. Also I modified grid parameters listbox and label.
Hope this is what you are after, or it will help you to get there.
If you use both .grid() and .pack() Tkinter (python 2.x) or tkinter (python 3.x) will happily spend the rest of your life trying to find a way to satisfy both, you must use one within the same window or Frame, see http://www.openbookproject.net/py4fun/gui/tkPhone.html

TKinter: I cannot see my left frame with a button inside

I cannot see my left frame with a button inside (I'm using TKinter).. This is my code:
#create window & frames
root = Tk()
root.title( "Medical Visualization" )
rootFrame = Frame(root)
rootFrame.pack( fill=BOTH, expand=1, side=TOP )
leftframe = Frame(root, width=100, bg="blue")
leftframe.pack(fill=X, expand=True)
button = Button(leftframe, text="Add Isosurface", fg="red")
button.pack( side = LEFT)
root.mainloop()
thanks
I see it, and looking at the code I see nothing that would prevent it from being seen. Are you remembering to call root.mainloop? Your code snippet doesn't show you calling that method.

Categories

Resources