tkinter insert widget in a frame - python

I am trying to make the following layout
tkinter layout
but the ID: label and the entry box are center left , and center right when then they should be next to each other , and they keep getting separated by the grid
I am also trying to use a for loop to make the number pad but im not sure how to make a new variable outside of the loops, and increment by 1 in the loop that creates the button
from tkinter import *
window = Tk()
#BOTTOM FRAME SECTION
bottomframe = Frame(window,bg="cyan", width =900, height = 100)
bottomframe.pack(fill=BOTH,side=BOTTOM)
button = Button(window,text="LOG IN")
button.pack(fill=BOTH,side=BOTTOM)
checkbutton = Checkbutton(window, text="Use pseudonym?")
checkbutton.pack(side=BOTTOM)
topframe = Frame(window,bg="red",width =900, height = 100)
topframe.pack(fill=BOTH,side=TOP)
label1 = Label(window, text="Majestic 12 Identifier")
label1.pack(side=TOP)
label2 = Label(window, text="ID")
label2.pack(side=LEFT)
label3 = Label(window,text="Enter keycode:")
label3.pack(side=TOP)
entry1 = Entry(window)
entry1.pack(side=LEFT)
#GRID SECTION
frame = Frame(window)
frame.pack(fill=BOTH,side=BOTTOM)
n = +1
for i in range(3):
Grid.rowconfigure(frame,i,weight=1)
Grid.columnconfigure(frame,i,weight=1)
for i in range(3):
b = Button(frame, text="%d" % (i+n))
for j in range(3):
b = Button(frame, text="%d" % (j+1))
b.grid(row=i, column=j,ipadx=2,ipady=2,padx=2,pady=2,sticky= W+E+N+S)
window.mainloop()
any help is welcome

Ok, I gave it a try. I played around a bit with the Frame objects. I deleted one, that was not needed. And I introduced topframe2 in order to make it possible for label2 and entry1 to be in the same row.
Watch carefully the parent of the various entries and labels. Not everything should get the window object as direct parent.
I am using expand and fill arguments - here I am basically applying what I just learned at Textbox not expanding with containing frame - TKinter and tkinter gui layout using frames and grid
from tkinter import *
window = Tk()
# BOTTOM FRAME SECTION
topframe = Frame(window, width=900, height=100)
topframe.pack(fill=BOTH, side=TOP)
label1 = Label(topframe, text="Majestic 12 Identifier")
label1.pack(side=TOP, fill=BOTH, expand=1)
topframe2 = Frame(topframe, width=900, height=100)
topframe2.pack(fill=BOTH, side=TOP)
label2 = Label(topframe2, text="ID")
label2.pack(side=LEFT)
entry1 = Entry(topframe2)
entry1.pack(side=LEFT, fill=X, expand=1)
label3 = Label(window, text="Enter keycode:")
label3.pack(side=TOP)
# GRID SECTION
frame = Frame(window)
frame.pack(fill=BOTH, side=TOP, expand=1)
n = +1
for i in range(3):
Grid.rowconfigure(frame, i, weight=1)
Grid.columnconfigure(frame, i, weight=1)
for i in range(3):
b = Button(frame, text="%d" % (i + n))
for j in range(3):
b = Button(frame, text="%d" % (j + 1))
b.grid(row=i, column=j, ipadx=2, ipady=2, padx=2, pady=2, sticky=W + E + N + S)
button = Button(window, text="LOG IN")
button.pack(fill=BOTH, side=BOTTOM)
checkbutton = Checkbutton(window, text="Use pseudonym?")
checkbutton.pack(side=BOTTOM)
if __name__ == '__main__':
window.mainloop()

Related

How can I change the shape of the scrollbar in tkinter, python?

I use scrollbar widget and I want to change the shape of it.
Here's my questions below.
Can I use the image on the scroll bar?
How can I modify the color and shape with the options like relief, background, highlightbackground, highlightcolor or highlightthickness? I already tried but not a thing has changed.
from tkinter import *
root = Tk()
root.geometry("640x480")
frame = Frame(root)
frame.pack()
scrollbar = Scrollbar(frame, relief=RAISED, width=20, bd=5, activebackground="yellow", elementborderwidth=10, troughcolor="yellow", highlightbackground="red")
scrollbar.pack(side="right", fill="y")
listbox = Listbox(frame, selectmode="extended", height=10, bg="green", fg="white", yscrollcommand=scrollbar.set)
for i in range(1, 32):
listbox.insert(END, str(i) + "day")
listbox.pack()
scrollbar.config(command = listbox.yview) # scrollbar와 listbox를 mapping 해줌
root.mainloop()

Making a tkinter horizontal scroll bar with grid python

So im having trouble making a horizontal scroll bar with grid and have been trying to mix and match different parameters and such and I've hit a rock with this tutorial
https://newbedev.com/tkinter-canvas-scrollbar-with-grid
being the first example
this is my code so far
window = tk.Tk()
window.geometry("1200x600")
frame_main = tk.Frame(window, bg="gray")
frame_main.grid(sticky='news')
# Create a frame for the canvas with non-zero row&column weights
frame_canvas = tk.Frame(frame_main)
frame_canvas.grid(row=0, column=0, pady=(5, 0), sticky='nw')
frame_canvas.grid_rowconfigure(0, weight=1)
frame_canvas.grid_columnconfigure(0, weight=1)
# Add a canvas in that frame
canvas = tk.Canvas(frame_canvas, bg="yellow")
canvas.grid(row=2, column=2, sticky="news")
# Link a scrollbar to the canvas
vsb = tk.Scrollbar(window, orient="horizontal", command=canvas.xview)
vsb.grid(row=0, column=2, sticky='we')
canvas.configure(xscrollcommand=vsb.set)
frame_canvas.config(width=first5columns_width + vsb.winfo_width(),height=first5rows_height)
canvas.config(scrollregion=canvas.bbox("all"))
col_0_head = tk.Label(window, text = " Adventures_Sherlock_Holmes.txt ", pady = 20) # pady = 20 gives some vertical
# separation between this row and the next
col_0_head.grid(row = 0, column = 0)
col_1_head = tk.Label(window, text = " Age_Innocence.txt ")
col_1_head.grid(row = 0, column = 1)
col_2_head = tk.Label(window, text = " Alice_Wonderland.txt ")
col_2_head.grid(row = 0, column = 2)
window.mainloop()
If you want to create a scroll bar in tkitner using grid option, you can simply create a scrollframe and pack the scrollbar in that frame
This is the type of code you can write:
scrollframe = Frame(root)
scrollframe.grid(...)
scrollx = Scrollbar(scrollframe, orient=HORIZONTAL)
scrollx.pack(expand=1, fill=X, side=BOTTOM)
This should ideally work if you don't want the scrollbar to fill your entire GUI Bottom X-axis. In case you are ok with it filling the entire GUI, then just pack the scrollbar in your root or Tk widget.
Thank You!
Two problems in your code.
The first is no scrollregion in canvas.
The second is wrong grid row and column values.
Here's a code snippet that solves your problem.
# Add a canvas in that frame
canvas = tk.Canvas(frame_canvas, bg="yellow", scrollregion = "0 0 2000 2000")
canvas.grid(row=2, column=2, sticky="news")
# Link a scrollbar to the canvas
vsb = tk.Scrollbar(window, orient="horizontal", command=canvas.xview)
vsb.grid(row=1, column=0, sticky='ew')
canvas.configure(xscrollcommand=vsb.set)

Python tkinker resitze Canvas

I have an Python3 Tkinter Programm. I have 3 Frames in the Main Window and in one Frame an canvas with scroll Option - now i want resitze the Canvas Area .
Now if i resize it moves the Scroll Bar for Y out the Window and the scrollbar for x works also not as expected (get bigger but slide area don't change)
How i Mange it to resize an Canvas in an grid Layout - The Window must be the same size , the Scrollbas must be updatet and the Canvas Plane must be bigger.
an excerpt from my code:
import tkinter as tk
def menu_build():
caninfo[0] += 10
cangui.configure(width = caninfo[0])
#cangui.configure(scrollregion=cangui.bbox("all"))
def gui():
master = tk.Tk()
master.title( "Easy Switch" )
master.geometry("480x320")
frametop = tk.Frame(master, bg="blue", bd=2)
frametop.grid(column=0,row=0)
frameex = tk.Frame(master, bg="yellow", bd=2)
frameex.grid(column=1,row=1)
framegui = tk.Frame(master, bg="red", bd=2)
framegui.grid(column=0, columnspan=2, row=1)
menu = tk.Menu(master)
master.config(menu=menu)
filemenu = tk.Menu(menu)
menu.add_cascade(label="Config", menu=filemenu)
filemenu.add_command(label="Resize",command=menu_build)
global cangui
cangui = tk.Canvas(framegui, width=385, height=250)
#caninfo = [385,250]
cangui.grid(row=1, column=2)
scroll_x = tk.Scrollbar(framegui, orient="horizontal", command=cangui.xview)
scroll_x.grid(row=2, column=2, sticky="ew")
scroll_y = tk.Scrollbar(framegui, orient="vertical", command=cangui.yview)
scroll_y.grid(row=1, column=3, sticky="ns")
cangui.configure(yscrollcommand=scroll_y.set,xscrollcommand=scroll_x.set)
cangui.configure(scrollregion=cangui.bbox("all"))
cwcb = tk.Checkbutton(framegui, text="ccw").grid(row=2,column=0)
cangui.create_arc(90,90,110,110,style=tk.PIESLICE,width=4,start=0,extent=300)
master.mainloop()
global caninfo
caninfo = [385,250]
if __name__ == "__main__":
gui()
no need to resize the canvas Area
wrote an extra funktion
win = [int(cangui.cget("width")),int(cangui.cget("height"))]
draw_xy = cangui.bbox("all")
swin = (min(0,draw_xy[0]),min(0,draw_xy[1]),max(draw_xy[2],win[0]),max(draw_xy[3],win[1]))
cangui.configure(scrollregion=swin)
reason: canvas.bbox("all") gives only the positon from most upper/left grafic and i want 0/0

How to expand buttons and labels to fill the x axis in python tkinter?

This is a part of code from my school project.
from tkinter import *
from tkinter.font import Font
class student_window():
def __init__(self, master):
self.student_win = master
#window = Toplevel(self.master)
self.student_win.geometry("1280x720")
self.header1Font = Font(family='Helvetica', size=20)
self.optionFont = Font(family='Sans Serrif', size=20)
self.student_win.focus()
self.show_window()
def show_window(self):
print("ookk")
self.student_win.title("Student Window")
self.option_frame = Frame(self.student_win, width=200, height=720)
lbl_header = Label(self.option_frame,text="EXAMINATION", font=self.header1Font, fg='white', bg='#172D44').grid(row=0,column=0, sticky=NSEW)
lbl_welcome = Label(self.option_frame, text="Welcome,", fg='#E9F1F7', bg='#2A3F54').grid(row=1,column=0)
lbl_username = Label(self.option_frame, text="Username", fg='white', bg='#2A3F54').grid(row=2,column=0)
lbl_header2 = Label(self.option_frame, text="STUDENT CORNER", fg='white', bg='#2A3F54').grid(row=3, column=0)
self.btn_tests = Button(self.option_frame, text="Attempt Exam", fg='#E9F1F7', bg='#35495D', relief=FLAT)
self.btn_tests.grid(row=4,column=0, sticky=NSEW)
self.btn_attempts = Button(self.option_frame, text="Attempts", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_attempts.grid(row=5, column=0, sticky=NSEW)
self.btn_result = Button(self.option_frame, text="Result", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_result.grid(row=6, column=0, sticky=NSEW)
self.btn_goBack = Button(self.option_frame, text="Go Back", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_goBack.grid(row=7, column=0, sticky=NSEW)
self.option_frame.configure(bg='#2A3F54')
self.option_frame.grid(row=0, column=0)
self.option_frame.grid_propagate(0)
self.main_frame = Frame(self.student_win, width=880, height=720)
self.main_result_frame = Frame(self.main_frame)
self.main_result_frame.grid(row=0,column=0)
self.attempts_frame = Frame(self.main_frame)
self.attempts_frame.grid(row=0, column=0)
self.test_frame = Frame(self.main_frame)
lbl_test = Label(self.test_frame, text="In test frame").pack()
self.test_frame.grid(row=0,column=0)
self.main_frame.grid(row=0,column=1)
self.main_frame.grid_propagate(0)
self.info_frame = Frame(self.student_win, width=200, height=720)
self.btn_username = Button(self.info_frame, text="Username", relief=FLAT)
self.btn_username.grid(row=0,column=0)
self.userInfo_frame = Frame(self.info_frame)
self.info_frame.grid(row=0, column=2)
self.info_frame.grid_propagate(0)
root = Tk()
student_window(root)
root.mainloop()
And it looks something like this.
The Student Panel for my project
The whole window is divided into three frames and want to expand each label and button of the left frame(self.option_frame) to fill it horizontally. I tried doing sticky=EW and sticky=NSEW but still some space is left. How do I fix that?
You need to call self.option_frame.columnconfigure(0, weight=1) to make column 0 to use all the available horizontal space.
I was just trying some things and what I have found to be working is to make the label width bigger than than the frame then anchoring the text to the left.

Tkinter Entry Widgets in list all saving same data

I have a function called display_change that is in the middle of my tkinter GUI. I want the user to select a number and create the number of entry boxes that they select. I figured out how to do this with a for loop and putting each entry box into a list. However whenever I write something the same data is saved between all of the entry widgets.
I don't want to show all my code but can show the whole function that this is happening in.
import tkinter as tk
from tkinter.ttk import Frame, Button
labels = []
entries = []
class Application(Frame):
def __init__(self)
super().__init__()
self.mainFrame()
def mainFrame(self):
self.master.title("Setup")
self.pack(fill=tk.BOTH, expand=True)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = tk.Label(self, text="Follow the instructions on each page", bg="snow2")
lbl.grid(sticky=tk.W, pady=4, padx=5)
area = tk.Frame(self, bg="white")
area.grid(row=1, column=0, columnspan=3, rowspan=4,
padx=5, sticky=tk.E + tk.W + tk.S + tk.N)
# ----------Inside White Box ---------------------
lbl = tk.Label(area, text="Select the number of parts to create:")
lbl.grid(row=1, column=0)
choices = {0, 3, 4, 5, 6, 7, 8, 9, 10}
node_count = tk.IntVar()
node_count.set(0)
node_select = tk.OptionMenu(area, node_count, *choices,
command=lambda x: self.display_change(area, node_count.get()))
node_select.grid(row=1, column=2)
# -----------Outside Part-------------------------
abtn = Button(self, text="Thing 1")
abtn.grid(row=1, column=3, sticky=tk.W)
cbtn = Button(self, text="Thing 2")
cbtn.grid(row=2, column=3, pady=4, sticky=tk.W)
abtn2 = Button(self, text="Thing 3")
abtn2.grid(row=3, column=3, sticky=tk.W + tk.N)
cbtn2 = Button(self, text="Thing 4")
cbtn2.grid(row=3, column=3, pady=28, sticky=tk.W + tk.N)
hbtn = Button(self, text="Exit")
hbtn.grid(row=5, column=2, sticky=tk.W)
sbtn = Button(self, text="Save")
sbtn.grid(row=5, column=3, pady=3, sticky=tk.W)
sbtn = Button(self, text="Help")
sbtn.grid(row=5, column=0, sticky=tk.W)
def display_change(self, area, nodes):
"""Here is where the display is changed so what the user choose is correctly displayed"""
lower_label = tk.Label(area, text="Enter the value of each part")
lower_label.grid(row=2, column=0, sticky=tk.N + tk.W)
global labels, entries
for label in labels:
label.destroy()
for entry in entries:
entry.destroy()
labels = []
entries = []
# This loop creates the correct number of entry box's and labels. Each entry is stored separately
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part "+str(i+1)))
labels[i].place(x=10+(120*i), y=55)
entries.append(tk.Entry(area, text="Change"))
entries[i].place(x=10 + (120 * i), y=80, width=100)
else:
labels.append(tk.Label(area, text="part " + str(i + 1)))
labels[i].place(x=10 + (120 * i), y=105)
entries.append(tk.Entry(area, text="Change"))
entries[i].place(x=10 + (120 * i), y=160, width=100)
if __name__ == "__main__":
root = tk.Tk()
"""Calculate center of screen so popup is center"""
w = 650
h = 400
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
# This line prevents the user from changing the size of the window
root.resizable(width=False, height=False)
app = Application(root)
root.mainloop()
This is what it looks like when I type something:
All I typed was 'abcd' once but it went into all the entries
When you look at all the available config options in the documentation for tkinters Entry field text is not one of them. Most likely because textvariable is an available argument for the Entry field tkinter is seeing text as short for textvariable. So as a result what is happening is all of your Entry fields are being assigned the same text variable and when one entry changes that variable all of them update with the new string in that variable.
The correct way to write your for loop would be something like the following:
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part {}".format(i+1)))
labels[i].place(x=10+(120*i), y=55)
entries.append(tk.Entry(area))
entries[i].insert(0, "Change Ip") # adds text directly to an entry field
entries[i].place(x=10 + (120 * i), y=80, width=100)
else:
labels.append(tk.Label(area, text="Node {}".format(i+1)))
labels[i].place(x=10 + (120 * i), y=105)
entries.append(tk.Entry(area)
entries[i].insert(0, "Change Ip")
entries[i].place(x=10 + (120 * i), y=160, width=100)
I don't understand it completely, but the text keyword argument is associating all of the entries with the same string variable that is then stored and simultaneously updating everything.
Instead of passing the text keyword, you can use the "insert" method of the entry after instantiation to set the text in the entry.
Tkinter doesn't have the best documentation in the world, so I'm not totally sure what's going on with the text keyword. Will keep looking into it. Here is an MVCE that does not exhibit the problematic behavior:
import tkinter as tk
from tkinter.ttk import Frame, Button
labels = []
entries = []
def display_change(self, area, nodes):
"""Here is where the display is changed so what the user choose is correctly seen"""
lower_label = tk.Label(area, text="Enter the value of each part")
lower_label.grid(row=2, column=0, sticky=tk.N + tk.W)
global labels, entries
for label in labels:
label.destroy()
for entry in entries:
entry.destroy()
labels = []
entries = []
# This loop creates the correct number of entry box's and labels. Each entry is stored separately
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part "+str(i+1)))
labels[i].place(x=10+(120*i), y=55)
entries.append(tk.Entry(area))
entries[i].insert(0, "Change IP")
entries[i].place(x=10 + (120 * i), y=80, width=100)
root = tk.Tk()
display_change(None, root, 4)
root.mainloop()
The problem is because Entry widgets don't have a text option, which is why the initial value they display isn't "Change Ip". Entry widgets do have a textvariable option, which must be be set to a StringVar for you to be able retrieve the current text from it later using a var.get() call.
Below is a runnable version of your code that shows an example of how to do this in the display_change() method. An new global list has been added named textvars to hold the StringVars that go with each Entry widget. You can use entries in it to get the current text in each corresponding Entry.
import tkinter as tk
from tkinter.ttk import Frame, Button
labels = []
entries = []
textvars = []
class Application(Frame):
def __init__(self, master=None):
super().__init__(master)
self.mainFrame()
def mainFrame(self):
self.master.title("Tinc VM Setup")
self.pack(fill=tk.BOTH, expand=True)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = tk.Label(self, text="Follow the instructions on each page",
bg="snow2")
lbl.grid(sticky=tk.W, pady=4, padx=5)
area = tk.Frame(self, bg="white")
area.grid(row=1, column=0, columnspan=3, rowspan=4,
padx=5, sticky=tk.E + tk.W + tk.S + tk.N)
# ----------Inside White Box ---------------------
lbl = tk.Label(area, text="Select the number of parts to create:")
lbl.grid(row=1, column=0)
choices = {0, 3, 4, 5, 6, 7, 8, 9, 10}
node_count = tk.IntVar()
node_count.set(0)
node_select = tk.OptionMenu(area, node_count, *choices,
command=lambda x: self.display_change(area, node_count.get()))
node_select.grid(row=1, column=2)
# -----------Outside Part-------------------------
abtn = Button(self, text="Thing 1")
abtn.grid(row=1, column=3, sticky=tk.W)
cbtn = Button(self, text="Thing 2")
cbtn.grid(row=2, column=3, pady=4, sticky=tk.W)
abtn2 = Button(self, text="Thing 3")
abtn2.grid(row=3, column=3, sticky=tk.W + tk.N)
cbtn2 = Button(self, text="Thing 4")
cbtn2.grid(row=3, column=3, pady=28, sticky=tk.W + tk.N)
hbtn = Button(self, text="Exit")
hbtn.grid(row=5, column=2, sticky=tk.W)
sbtn = Button(self, text="Save")
sbtn.grid(row=5, column=3, pady=3, sticky=tk.W)
sbtn = Button(self, text="Help")
sbtn.grid(row=5, column=0, sticky=tk.W)
def display_change(self, area, nodes):
"""Here is where the display is changed so what the user choose is
correctly displayed.
"""
lower_label = tk.Label(area, text="Enter the value of each part")
lower_label.grid(row=2, column=0, sticky=tk.N + tk.W)
global labels, entries, textvars
for label in labels:
label.destroy()
for entry in entries:
entry.destroy()
labels = []
entries = []
textvars = []
# This loop creates the correct number of entry box's and labels.
# Each entry is stored separately
for i in range(nodes):
if nodes <= 4:
labels.append(tk.Label(area, text="Part "+str(i+1)))
labels[-1].place(x=10+(120*i), y=55)
textvars.append(tk.StringVar())
textvars[-1].set("Change Ip")
entries.append(tk.Entry(area, textvariable=textvars[-1]))
entries[-1].place(x=10 + (120 * i), y=80, width=100)
else:
labels.append(tk.Label(area, text="Node " + str(i + 1)))
labels[-1].place(x=10 + (120 * i), y=105)
textvars.append(tk.StringVar())
textvars[-1].set("Change Ip")
entries.append(tk.Entry(area, textvariable=textvars[-1]))
entries[-1].place(x=10 + (120 * i), y=160, width=100)
if __name__ == "__main__":
root = tk.Tk()
"""Calculate center of screen so popup is center"""
w = 650
h = 400
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
# This line prevents the user from changing the size of the window
root.resizable(width=False, height=False)
app = Application(root)
root.mainloop()
The variable should by specified in Entry by textvariable and defined at the beginning using StringVar(), check the following code
from Tkinter import *
import ttk
root = Tk()
root.title("GUI titile")
root.geometry("200x100")
variable1 = StringVar()
variable2 = StringVar()
entry1 = Entry(root,textvariable=variable1)
entry1.pack()
entry2 = Entry(root,textvariable=variable2)
entry2.pack()
root.mainloop()
GUI output image :
NOTE: imports differ according to python version

Categories