Setting borderwidth of a frame doesn't show a border - python

I follow the tutorials online and the documentations but still can't add a border to a frame. The following is the code I run
import tkinter as tk
root = tk.Tk()
frame1 = tk.Frame(root, borderwidth=2 )
frame2 = tk.Frame(root, borderwidth=2 )
frame1.grid(row = 0)
frame2.grid(row = 1)
tk.Label(frame1, text = 'frame1').grid(row = 0)
tk.Label(frame2, text = 'frame2').grid(row = 0)
root.mainloop()
And this is the result I got. What's the problem?

You need to set the relief option to one of "raised", "sunken", "ridge", or "groove". On your system it appears the default is "flat". The final option is "solid".

Related

Create scrollbar in tKinter without displacing widgets to the left (python)

I'm creating a program by learning from youtube tutorials (I'm a complete beginner) and I have come to some difficulties. This time, I'm trying to create a scrollbar, and I want my widgets to stay on the center of my window, not the left (I'm following the Codemy.com tutorial on scrollbars).
Here is the current aspect of my program:
with scrollbar
And here is how I want it to look:
without scrollbar
This is my code right now:
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
my_canvas = tk.Canvas(root)
my_canvas.pack(side = "left", fill = "both", expand = 1)
my_scrollbar = tk.Scrollbar(root, orient = "vertical", command = my_canvas.yview)
my_scrollbar.pack(side = "right", fill = "y")
my_canvas.configure(yscrollcommand = my_scrollbar.set)
my_canvas.bind("<Configure>", lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
my_frame = tk.Frame(my_canvas)
for i in range(100):
my_label = tk.Label(my_frame, text = "Label")
my_label.pack()
my_canvas.create_window((0,0), window = my_frame, anchor = "nw")
root.mainloop()
Include width = 600, anchor = "nw" in my_canvas declaration.
my_canvas.create_window((0,0), window = my_frame, width = 600, anchor = "nw")

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()

How to put a horizontal frame containing a couple of widgets into a default vertical frame?

I have a layout that is vertical, with some horizontal rows containing a few widgets. When I add the first row it goes fine, but the second row goes at the end of the first row and not back in the vertical frame
I've tried everything I can find with no luck.
import tkinter
win = tkinter.Tk()
frame2 = tkinter.Frame()
frame3 = tkinter.Frame()
frame2.pack()
frame3.pack()
lv1 = tkinter.Label(win, text = "Vertical lab 1")
lv1.pack()
lv2 = tkinter.Label(win, text = "Vertical lab 2")
lv2.pack()
v = tkinter.IntVar()
rb1 = tkinter.Radiobutton(frame2, padx = 10, variable=v,value=1)
rb1.pack()
lh1 = tkinter.Label(frame2, text = "Horizontal lab1")
lh1.pack()
frame2 = tkinter.Frame(win).pack()
rb2 = tkinter.Radiobutton(frame3, padx = 10, variable=v, value=2)
rb2.pack()
lh2 = tkinter.Label(frame3, text = "Horizontal lab2")
lh2.pack()
frame3 = tkinter.Frame(win).pack()
lv3 = tkinter.Label(win, text = "Vertical lab 3")
lv3.pack(anchor="w")
win.mainloop()
What I want is something that looks like: One widget on line 1, one widget on line 2, 2 widgets on line 3, 2 widgets on line 4, 1 widget on line 5
I couldn't find a solution using .pack() so I decided to use .grid() for labels, radiobuttons inside the frames.
from tkinter import *
window = Tk()
frame1 = Frame(window)
Label(frame1, text = "Vertical lab 1").grid(row = 0, column = 0)
Label(frame1, text = "Vertical lab 2").grid(row = 1, column = 0)
frame1.pack()
v = IntVar()
frame2 = Frame(window)
rb1 = Radiobutton(frame2, padx = 10, variable=v,value=1)
rb1.grid(row = 0, column = 0)
Label(frame2, text = "Horizontal lab1").grid(row = 0, column = 1)
rb2 = Radiobutton(frame2, padx = 10, variable=v,value=1)
rb2.grid(row = 1, column = 0)
Label(frame2, text = "Horizontal lab1").grid(row = 1, column = 1)
frame2.pack()
frame3 = Frame(window)
Label(frame3, text = "Vertical lab 3").grid(row = 0, column = 0)
frame3.pack()
window.mainloop()
The output looks like this I presume this is what you were looking for.
Also I would like to mention when you use a geometry manager in the same line as you declare it, for example frame1 = tkinter.Frame().pack(), here frame1 is None and so is everything else in your code of type None, therefore you need to place it afterwards.
As mentioned here https://effbot.org/tkinterbook/pack.htm don't use .pack() and .grid() in the same master window.
The answer is very simple.
A widget and a frame containing widget, have a different weight/priority when being placed into a parent window-frame.
Just put ALL widgets into frames, then when they are added to the parent window-frame they will all have the same weight/priority and will appear in the order they were added.
I tested this method and it works perfectly.
(But surely it should not be necessity to do this. Am I still missing something? The corresponding Java layout manager does NOT have this issue! Widgets and frames containing widgets are treated the same.)
For positioning use tkinter grid option:
from tkinter import *
window = Tk()
window.geometry('600x400')
# set widget object
label = Label(window, text="Vertical lab 1")
# set position of widget into grid
label.grid(column=0, row=0)
label = Label(window, text="Vertical lab 2")
label.grid(column=0, row=1)
label = Radiobutton(window, text="Horizontal lab 1", value=0)
label.grid(column=0, row=2)
label = Radiobutton(window, text="Horizontal lab 2", value=1)
label.grid(column=1, row=2)
label = Radiobutton(window, text="Horizontal lab 3", value=0)
label.grid(column=0, row=3)
label = Radiobutton(window, text="Horizontal lab 4", value=1)
label.grid(column=1, row=3)
label = Label(window, text="Vertical lab 3")
label.grid(column=0, row=4)
window.mainloop()

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