python tkinter button in frame - python

It feels this should be easy but not as much as I would hope. All I want to do is put a button in a frame. My code is coloring the frame so I can validate the button is where I want to put it and as you can see, below, my code is not doing what I want/think. I expect my code to put the radio button inside the yellow frame - not under it.
from tkinter import *
class apiMain:
def main(self):
master=Tk()
topframe = Frame(master, bg="Lemon chiffon", width=500, height=50).pack(side = TOP)
v = IntVar()
crbutton = Radiobutton(topframe, text = "change request", variable = v, value = 'cr')
crbutton.pack(side = LEFT, padx = 10)
mainloop()

When you assign topframe like this:
topframe = Frame(master, bg="Lemon chiffon", width=500, height=50).pack(side = TOP)
You are essentially writing topframe = None, because pack() always returns None. Because of this, you're assigning the master of your radio button to None which defaults to the main window. Split your code up, so that topframe references the actual Frame object:
topframe = Frame(master, bg="Lemon chiffon", width=500, height=50)
topframe.pack(side = TOP)

Related

How make tkinter grid_forget resize LabelFrame?

I have a frame that holds buttons and it's packed in a LabelFrame with grid geometry manager.
When I remove this frame with grid_forget, the LabelFrame still has the same size.
With other words
it doesn't shrink.
Here is the code, when you press the button all the buttons are removed
but the size remains.
I expected that the grid geometry manager deals automatically with resizing when widgets are removed.
import tkinter as tk
class Collapsible():
def __init__(self, master):
self.master = master
self.dynamic_widgets()
self.fill_lb()
def dynamic_widgets(self):
"""create widgets"""
#frame that holds labelwidgets
self.fr_collapse = tk.Frame(self.master, bg="orange")
#title for label frame----------------------------------------------------------------
self.bt_title = tk.Button(self.fr_collapse, text="o",
highlightthickness = 0, bd = 0,
relief="flat", bg="orange", fg="red")
self.bt_title.grid(row=0, column=0)
self.label_title = tk.Label(self.fr_collapse, text="Name", bg="orange")
self.label_title.grid(row=0, column=1)
#-------------------------------------------------------------------------------------
self.label_frame = tk.LabelFrame(self.master,
bg="orange", labelwidget=self.fr_collapse)
self.label_frame.grid(sticky="wesn", ipady=(10))
#frame for buttons
self.frame_forget = tk.Frame(self.label_frame, bg="orange")
self.frame_forget.grid()
#set command
self.bt_title.configure(command=lambda x=self.frame_forget, y=self.bt_title: self.hide(x, y))
def fill_lb(self):
"fill label frame with dumb buttons"""
b = tk.Button(self.frame_forget, text="Example button 1", bg="orange", relief="flat")
b.grid()
b2 = tk.Button(self.frame_forget, text="Example button 2", bg="orange", relief="flat")
b2.grid()
def hide(self, frame, button):
"""switch value: hide frame based on text configuration"""
bt_text = button.configure("text")
if bt_text[-1] == "o":
frame.grid_remove()
button.configure(text="-")
else:
frame.grid()
button.configure(text="o")
if __name__ == "__main__":
root = tk.Tk()
col = Collapsible(root)
root.configure(bg="orange")
root.mainloop()
What I tried so far:
I thought that maybe I need to grid frame that holds buttons after deleting them. Does'n work because this will
grid my hidden buttons again which is logically.
I thought that maybe I need to grid the LableFrame again. No changes in size either
I thought that maybe I should put a dumb frame like a placeholder with minimal width and height values.
and grid it as child in my frame_forget frame with the hope that it will shrink. But still nothing.
None of those thoughts brought me a solution and the question remains
When I run my script it looks like this:
Then when I press flat button in the left corner 'o', I get this:
I wish it would collapse like this one:

Why isn't this frame in tkinter centered correctly?

I want this entry bar and other contents I'll add to the frame later to be centred correctly, I received this code that supposedly should work but it isn't.
import tkinter as tk
import math
import time
root = tk.Tk()
root.geometry()
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text = "Exit", command = root.destroy)
exit_button.place(x=1506, y=0)
frame = tk.Frame(root)
main_entry = tk.Entry(root, width = 100, fg = "black")
main_entry.place(x=50, y=50)
frame.place(relx=.5,rely=.5, anchor='center')
root.mainloop()
As you can see the frame isn't centred so how can I fix this?
In order to achieve widget centering on a fullscreen I've had to use grid manager.
The code below works but the exact positioning requires some fiddling with frame padding.
frame padx = w/2-300 and pady = h/2-45 are arbitrary values found using a bit of trial and error.
import tkinter as tk
root = tk.Tk()
root.attributes( '-fullscreen', True )
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
frame = tk.Frame( root )
main_entry = tk.Entry( frame, width = 100 )
main_entry.grid( row = 0, column = 0, sticky = tk.NSEW )
frame.grid( row = 0, column = 0, padx = w/2-300, pady = h/2-45, sticky = tk.NSEW )
exit_button = tk.Button( frame, text = 'Exit', command = root.destroy )
exit_button.grid( row = 1, column = 0, sticky = tk.NSEW )
tk.mainloop()
Frame automatically changes size to size of objects inside Frame (when you use pack()) but you have nothing inside Frame. You put all widgets directly in root - so Frame has no size (width zero, height zero) and it is not visible.
When I use tk.Frame(root, bg='red', width=100, height=100) then I see small red frame in the center.
You have two problems:
(1) you put Entry in wrong parent - it has to be frame instead of root,
(2) you use place() which doesn't resize Frame to its children and it has size zero - so you don't see it. You would have to set size of Frame manully (ie. tk.Frame(..., width=100, height=100)) or you could use pack() and it will resize it automatically.
I add colors for backgrounds to see widgets. blue for window and red for frame.
import tkinter as tk
root = tk.Tk()
root['bg'] = 'blue'
root.attributes("-fullscreen", True)
exit_button = tk.Button(root, text="Exit", command=root.destroy)
exit_button.place(x=1506, y=0)
frame = tk.Frame(root, bg='red')
frame.place(relx=.5, rely=.5, anchor='center')
main_entry = tk.Entry(frame, width=100, fg="black")
main_entry.pack(padx=50, pady=50) # with external margins 50
root.mainloop()

Scrollbar into a python tkinter discussion

from tkinter import *
window = Tk()
ia_answers= "test\n"
input_frame = LabelFrame(window, text="User :", borderwidth=4)
input_frame.pack(fill=BOTH, side=BOTTOM)
input_user = StringVar()
input_field = Entry(input_frame, text=input_user)
input_field.pack(fill=BOTH, side=BOTTOM)
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
canvas = Canvas(window, borderwidth=0, background="white")
ia_frame = LabelFrame(canvas, text="Discussion",borderwidth = 15, height = 100, width = 100)
ia_frame.pack(fill=BOTH, side=TOP)
scroll = Scrollbar(window, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scroll.set)
scroll.pack(side=RIGHT, fill=Y)
canvas.pack(fill=BOTH, expand=True)
canvas.create_window((4,4), window=ia_frame, anchor="nw")
ia_frame.bind("<Configure>", lambda event, canvas=canvas:onFrameConfigure(canvas))
user_says = StringVar()
user_text = Label(ia_frame, textvariable=user_says, anchor = NE, justify = RIGHT, bg="white")
user_text.pack(fill=X)
ia_says = StringVar()
ia_text = Label(ia_frame, textvariable=ia_says, anchor = NW, justify = LEFT, bg="white")
ia_text.pack(fill=X)
user_texts = []
ia_texts = []
user_says_list = []
ia_says_list = []
def Enter_pressed(event):
"""Took the current string in the Entry field."""
input_get = input_field.get()
input_user.set("")
user_says1 = StringVar()
user_says1.set(input_get + "\n")
user_text1 = Label(ia_frame, textvariable=user_says1, anchor = NE, justify = RIGHT, bg="white")
user_text1.pack(fill=X)
user_texts.append(user_text1)
user_says_list.append(user_says1)
ia_says1 = StringVar()
ia_says1.set(ia_answers)
ia_text1 = Label(ia_frame, textvariable=ia_says1, anchor = NW, justify = LEFT, bg="white")
ia_text1.pack(fill=X)
ia_texts.append(ia_text1)
ia_says_list.append(ia_says1)
input_field.bind("<Return>", Enter_pressed)
window.mainloop()
Hi, I try to build a GUI with tkinter but I've got two problems, the LabelFrame/Canvas doesn't fill entirely the window and I can't get the scrollbar to automatically scroll down.
Can you help me with that, thank you very much.
Ilan Rossler.
You need to manually control the width of the inner frame since it is being managed by the canvas. You can change the width in a binding to the <Configure> event of the canvas (ie: when the canvas changes size, you must change the size of the frame).
You'll need to be able to reference the window object on the canvas, which means you need to save the id, or give it a tag.
Here's an example of giving it a tag:
canvas.create_window((4,4), window=ia_frame, anchor="nw", tags=("innerFrame",))
And here's how to change the width when the canvas changes size:
def onCanvasConfigure(event):
canvas = event.widget
canvas.itemconfigure("innerFrame", width=canvas.winfo_width() - 8)
canvas.bind("<Configure>", onCanvasConfigure)
To scroll down, call the yview command just like the scrollbar does. You need to make this happen after the window has had a chance to refresh.
For example, add this as the very last line in Enter_pressed:
def Enter_pressed(event):
...
canvas.after_idle(canvas.yview_moveto, 1.0)

Python tkinter grid layout problems

I'm creating a very simple UI using Tkinter and python, but I'm having trouble sizing GUI elements and using the grid format to place them correctly. Here's a first-order approximation of what I'm trying to have:
Here's the code I have so far. I keep getting close, but I don't think I really understand what I'm doing. Any help is much appreciated!
#User interface
root = Tk()
window_width = root.winfo_screenwidth()
window_height = root.winfo_screenheight()
root.geometry ("%dx%d"%(window_width,window_height))
menu_bar = Menu(root)
menu = Menu(menu_bar, tearoff=0)
menu.add_command(label="Open", command = open_file)
menu.add_command(label="Save", command = save)
menu.add_separator()
menu.add_command(label="Quit", command = exit)
menu_bar.add_cascade(label="File",menu=menu)
root.config(menu=menu_bar)
#textbox is the window in which the code is written
textbox = Text(root, width=50, height = window_height/20+4)
#canvas is where the car will go
canvas_frame= Frame(root, width = window_width/1.5, height = window_height-200)
canvas_frame.configure(borderwidth=1.5,background='black')
canvas = Canvas(canvas_frame, width = window_width/1.5, height = window_height-200)
#console to print to
console = Text(root, width = int(window_width/1.5), height = 10)
run_button = Button(root, text = "Run", command = lambda:generate_program(textbox.get(1.0,END)))
clear_button = Button(root, text = "Clear text", command = clear)
#add them to frame
textbox.grid(row=0, column=0, rowspan=20, columnspan=10)
run_button.grid(row=21,column=0)
clear_button.grid(row=21,column=1)
canvas_frame.grid(row=0,rowspan=10,column=21,columnspan=25)
canvas.grid(row=0, rowspan=1, column=21, columnspan=25)
console.grid(row = 1, rowspan=1, column = 21, columnspan=25)
root.mainloop()
In my opinion, this is layout can be much easier with the pack geometry manager. One of the problems is that you are trying to make the width and the height of each widget fit in its place with rowspan and columspan options. Also, since canvasis inside a frame, you have to think that it is like inside a new window, so a simple call to canvas.grid() would be enough.
However, with pack() you just have to put textbox, run_button and clear_button inside a new frame:
left_frame = Frame(root)
textbox = Text(left_frame, ...)
run_button = Button(left_frame, ...)
clear_button = Button(left_frame, ...)
canvas_frame= Frame(root, ...)
canvas_frame.configure(borderwidth=1.5,background='black')
canvas = Canvas(canvas_frame, ...)
console = Text(root, ...)
left_frame.pack(side=LEFT)
textbox.pack()
run_button.pack(side=LEFT)
clear_button.pack()
canvas_frame.pack()
canvas.pack()
console.pack()

How to use Grid Layout manager for arranging two buttons in desried location in frame?

I have been started Learning TK (From Python). I felt that i could use Grid Layout manager for displaying widgets (It sounds easy) but now i am feeling it was a wrong decision. For example i was just planning a frame which inside it was having multiple frames (Wizard Like form). So in the bottom of that form i wanted to have two buttons (Next, Previous). Now i wanted to place them on the very right of the bottom frame, but it seems to be difficult in having such an arrangement.
i tried creating seperate internal frames for both the buttons but could not get my result. Can some one tell me if i can achieve such a result with grid layout manager
from Tkinter import *
tk = Tk()
main_frame = Frame(tk)
main_frame.grid(row=0)
frame3 = Frame(main_frame, bg="orange", width=1000, height=100)
frame3.grid(row=1,column=0,columnspan=2)
frame3a = Frame(frame3)
frame3b = Frame(frame3)
frame3a.grid(row =0 ,column = 0)
frame3b.grid(row = 0, column = 1)
btn1 = Button(frame3a, text='Next', width = 10, command=next)
btn1.grid(padx=200, pady =40 )
btn2 = Button(frame3b, text='Previous', width = 10, command=prev)
btn2.grid(padx=00, pady =40 )
frame3.grid_propagate(False)
tk.mainloop()
thanks in advance
yes you can. Use more row/column attributes from grid as well as the sticky attribute.
Read: http://effbot.org/tkinterbook/grid.htm
I am assuming you want your window to look something like this (crude ascii incoming)
+------------+------------+
| | |
| FRAME | FRAME |
|------------+------------|
| FRAME |PREV|NEXT|
+-------------------------+
To do this I would use pack rather than grid. I make a bottom frame and make it just the height of the buttons, then pack them both right: If you want to stick other crap in that bottom sace, you can use grid manager to shove the frame out of the way. Pack is only active in the frame with the buttons in it, but you can use gridmanager to move the buttonframe around.
from Tkinter import *
tk = Tk()
main_frame = Frame(tk)
main_frame.grid(row=0)
frame1 = Frame(main_frame, bg="orange", width=500, height=100)
frame2 = Frame(main_frame, bg="blue", width=500, height=100)
frame3 = Frame(main_frame, bg="green", width=1000, height=50)
frame1.grid(row=1,column=1)
frame2.grid(row=1,column=2)
frame3.grid(row=2,column=1,columnspan=2)
frame3.pack_propagate(0) # Keeps bottom frame from resizing
btn1 = Button(frame3, text='Next', width = 10)
btn1.pack(side='right') # sticks on side
btn2 = Button(frame3, text='Previous', width = 10)
btn2.pack(side='right') # sticks on side
tk.mainloop()

Categories

Resources