Change width of tkinter Entry box to match width of window - python-3.x

from tkinter import *
def show_entry_fields():
e2.insert(10,(e1.get()))
master = Tk()
master.minsize(width=900, height=20)
Label(master, text="Paste").grid(row=0)
Label(master, text="Output").grid(row=1)
e1 = Entry(master)
e2 = Entry(master)
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
Button(master, text='Quit', command=master.quit).grid(row=3, column=0, sticky=W, pady=4)
Button(master, text='Convert', command=show_entry_fields).grid(row=3, column=1, sticky=W, pady=4)
mainloop( )
I just started learning Python and tkinter. I want to make the two Entry boxes as wide as the entire window. But even as I make the window larger, the Entry fields are confined to the first column of the "grid" and do not expand. How can I make the entry fields wider?

From http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/grid-config.html
w.columnconfigure(N, option=value, ...)
weight To make a column or row stretchable, use this option and supply a value that gives the relative weight of this column or row when distributing the extra space. For example, if a widget w contains a grid layout, these lines will distribute three-fourths of the extra space to the first column and one-fourth to the second column:
w.columnconfigure(0, weight=3)
w.columnconfigure(1, weight=1)
If this option is not used, the column or row will not stretch.
So in your case
master.columnconfigure(1, weight=1)
along with updating sticky attribute of e1 (and e2), as pointed out by #BryanOakley:
e1.grid(row=0, column=1, sticky=W+E)
should do the trick.

I have a similar example you can try this:
from Tkinter import *
root = Tk()
row1 = Frame(root)
row1.grid(row=0, column=0, sticky=N+S+E+W)
row2 = Frame(root)
row2.grid(row=1, column=0, sticky=N+S+E+W)
Label1 = Label(row1,text = "First")
Label2 = Label(row2,text = "Second")
entry1 = Entry(row1)
entry2= Entry(row2)
row1.pack(fill=X)
Label1.pack(side = LEFT)
entry1.pack(side = LEFT,fill=X,expand = True)
row2.pack(fill=X)
Label2.pack(side = LEFT)
entry2.pack(side = LEFT,fill=X,expand = True)
root.mainloop()

Related

Left Justifying entry box next to label in Tkinter?

So I was wondering why my entry boxes are showing in the center. Before I had the label instructions for first and last name they were aligning right. I have the labels on column 0 and the entry boxes on column 1, however they dont line up directly next to each other. If someone could help me with a very basic solution and language, I am obviously a beginner..
root = Tk()
root.title("Login Information Help")
root.configure(background='black')
root.geometry("1920x1080")
def button_click(number):
textbox.delete(0, END)
textbox.insert(0, number)
instructions = Label(root, text="Please fill in all information below to recieve student account details.", bg="black", fg="white", font="times, 20") #Create instructions line
first_name_text = Label(root, text="Enter First Name", bg="black", fg="white", font="times, 20" ) #enter first name text
inputbox1 = Entry(root, width=30, font="times, 20") #Create input boxes
last_name_text = Label(root, text="Enter Last Name", bg="black", fg="white", font="times, 20" ) #enter last name text
inputbox2 = Entry(root, width=30, font="Times, 20") #Create input boxes
button_1 = Button(root, text="Get Info", padx=45, pady=5, bg="#808080", font="times, 15", command=lambda: button_click("1")) #Define Buttons
instructions.grid(row=0, column=0) #Define Instructions variables (labels)
first_name_text.grid(row=1, column=0, pady=0, sticky=W) #position first name text
inputbox1.grid(row=1, column=1, padx=10) #Postion inputbox 1
last_name_text.grid(row=2, column=0, sticky=W) #position last name text
inputbox2.grid(row=2, column=1, padx=10, pady=10, sticky=W) #Postion inputbox 2
button_1.grid(row=3, column=0, sticky=W) #Put Buttons on Screen
root.mainloop()```
First row must span 2 columns.
instructions.grid(row=0, column=0, columnspan=2)
Use sticky=EW with every widget to fill the column.
Add root.columnconfigure(0, weight=0) to not expand the first column.
First of all this method uses pack since that is what I came up with (more explanation below) here is my code:
from tkinter import Tk, Label, Entry, Button, Frame
root = Tk()
root.title("Login Information Help")
root.configure(background='black')
root.geometry("1920x1080")
def button_click(number):
textbox.delete(0, END)
textbox.insert(0, number)
row0 = Frame(root, bg='black')
row0.pack(side='top', fill='y', anchor='nw')
row1 = Frame(root, bg='black')
row1.pack(side='top', fill='y', anchor='nw')
row2 = Frame(root, bg='black')
row2.pack(side='top', fill='y', anchor='nw')
row3 = Frame(root, bg='black')
row3.pack(side='top', fill='y', anchor='nw')
instructions = Label(row0, text="Please fill in all information below to recieve student account details.", bg="black", fg="white", font="times, 20") #Create instructions line
first_name_text = Label(row1, text="Enter First Name", bg="black", fg="white", font="times, 20" ) #enter first name text
inputbox1 = Entry(row1, width=30, font="times, 20") #Create input boxes
last_name_text = Label(row2, text="Enter Last Name", bg="black", fg="white", font="times, 20" ) #enter last name text
inputbox2 = Entry(row2, width=30, font="Times, 20") #Create input boxes
button_1 = Button(row3, text="Get Info", padx=45, pady=5, bg="#808080", font="times, 15", command=lambda: button_click("1")) #Define Buttons
instructions.pack(side='left')
first_name_text.pack(side='left')
inputbox1.pack(side='left')
last_name_text.pack(side='left')
inputbox2.pack(side='left', padx=2)
button_1.pack(side='left')
root.mainloop()
Explanation: those frames created at the top are stacked like rows, so whenever I add something to each of them using side argument in pack they get added there like columns, that padx is to make the alignment look nicer. Also I would suggest organizing the code better and start learning classes since they imo help a lot when dealing with tkinter.
So basically lets take one of the frames for example. the row1: when adding with .packand using one side (left in this case) widgets get packed in a row however it is not that easy to make them then packed in the second row so that is why there is another frame that is directly below the row1 called row2 and it gets directly packed underneath because of top side similarly as left side for widgets and those frames expand only where there are widgets (or maybe for that expansion it has to have the argument of fill, dunno rn) anyhow have a good day and experiment

Tkinter scroll bar will not control entry widgets

My scroll bar is supposed to be a child of Canvas_2 and controlling the y-value of Canvas_3. However it is not working as intended. The scroll bar doesn't move up or down, and there is also a blue region that shouldn't be visible. Any ideas on what I'm missing here? I really appreciate your time.
import tkinter as tk
from PIL import ImageTk, Image
# To initialize tkinter, we have to create a Tk root widget,
# which is a window with a title bar and other decoration
# provided by the window manager.
# The root widget has to be created before any other widgets
# and there can only be one root widget.
root = tk.Tk()
# The weight of a row or column determines how much of the
# available space a row or column should occupy relative to
# the other rows or columns. For example, a column with a
# weight of 2 will be twice as wide as a column with a
# weight of 1, assuming there's space for the widgets to fit.
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
load1 = Image.open("example.jpg")
render1 = ImageTk.PhotoImage(load1)
# Creating a class for filling each row
def makeRow(top, img, row):
r = row
if row == 0:
c1 = "#75dce1"
c2 = "#75dce1"
e7 = tk.Entry(top, bg=c2).grid(row=r, column=6, sticky="news")
e8 = tk.Entry(top, bg=c2).grid(row=r, column=7, sticky="news")
else:
c1 = "#a9d08e"
c2 = "#8dd1bf"
img = tk.Label(top, image=render1, bg="green").grid(row=r, column=6, sticky="news")
e1 = tk.Entry(top, bg=c1).grid(row=r, column=0, sticky="news")
e2 = tk.Entry(top, bg=c1).grid(row=r, column=1, sticky="news")
e3 = tk.Entry(top, bg=c1).grid(row=r, column=2, sticky="news")
e4 = tk.Entry(top, bg=c1).grid(row=r, column=3, sticky="news")
e5 = tk.Entry(top, bg=c2).grid(row=r, column=4, sticky="news")
e6 = tk.Entry(top, bg=c2).grid(row=r, column=5, sticky="news")
# load1 = Image.open(img)
# render1 = ImageTk.PhotoImage(load1)
# The canv_1 is a child of the parent "root"
# canv_1 contains: canv_2 (frozen top row) and canv_3 (bottom rows with a vertical scroll)
canv_1 = tk.Canvas(root, bg="blue")
canv_1.grid_rowconfigure(0, weight=1)
canv_1.grid_rowconfigure(1, weight=10)
canv_1.grid_columnconfigure(0, weight=1)
canv_1.grid(row=0, column=0, sticky = "news")
canv_1.grid(row=1, column=0, sticky = "news")
# The canv_2 is a child of the parent "canv_1"
canv_2 = tk.Canvas(canv_1, bg="blue")
canv_2.grid_rowconfigure(0, weight=1)
canv_2.grid_rowconfigure(1, weight=1)
canv_2.grid_columnconfigure(0, weight=1)
canv_2.grid(row=0, column=0, sticky = "news")
canv_2.grid(row=1, column=0, sticky = "news")
# The canv_3 is a child of the parent "canv_2"
canv_3 = tk.Canvas(canv_2, bg="blue")
canv_3.grid(row=1, column=0, sticky="news")
# canv_3.grid_rowconfigure((1,2,3,4,5), weight=1)
# canv_3.grid_columnconfigure((1,2,3,4,5), weight=1)
slides = []
for i in range(10):
slides.append(i)
if i==0:
slides[i] = makeRow(canv_3,"", 0)
else:
slides[i] = makeRow(canv_3, "example.jpg", i)
# Create Scrollbar
vsb = tk.Scrollbar(canv_2, orient="vertical", command=canv_3.yview)
vsb.grid(row=1, column=1, sticky='ns')
canv_2.configure(yscrollcommand=vsb.set)
canv_2.config(scrollregion=canv_3.bbox("all"))
canv_2.configure(scrollregion=(0, 0, 5000, 5000))
root.mainloop()
This is the actual output:
This is the desired design & output:
There are at least three fundamental problems with the code. The biggest problem is that you are adding widgets to canv_3 using grid. A canvas can't scroll items added to a canvas with grid. It will only scroll items added with the "create" methods of the canvas (create_window, create_text, etc).
The second problem is that you never define a proper scrollregion for canv_3, so even if you added the items with create_window, tkinter wouldn't know what the scrollable region is.
The third problem is that scrollbars require a two-way configuration. The scrollbar command needs to call the yview method of the widget, and the widget's yscrollcommand option needs to call the set method of the scrollbar.

Using Tkinter to disable entry with specified input

I would like to use Tkinter to be able to disable one entry if 'no' is selected from a drop down menu.
from tkinter import *
def disableEntry(entry):
entry.config(state='disable')
def allowEntry(entry):
entry.config(state='normal')
def main():
print("test")
root = Tk() #create a TK root window
root.title("Lunch and Learn") #Title of the window
L1 = Label(root, text = "Label 1").grid(row=0, column=0, padx=30, pady=(20,5))
L2 = Label(root, text = "Label 2").grid(row=1, column=0, pady=5)
var = StringVar()
E1 = Entry(root,bd =3)
E1.grid(row=0, column=1)
D1 = OptionMenu(root,var,"yes","no")
D1.grid(row=1,column=1)
if var.get() == 'no':
disableEntry(E1)
elif var.get() == 'yes':
allowEntry(E1)
B2 = Button(text = "Submit", command=main).grid(row=4, column=2)
root.mainloop()
the above code is a simple example of what i have tried. I have created two functions called 'disableEntry' and 'allowEntry' which should change the state of the entry box but they don't appear to do anything when i change the input of the drop down menu.
i dont know if i am approaching this the wrong way or if there is a standardized way to do this.
any help would be appreciated.
You need a way to check the state of the selection after it is changed. That can be achieved with adding a callback command to the OptionMenu widget.
You were checking the correct variable, but the point you were checking it at was before the screen window had even displayed.
from tkinter import Label, StringVar, OptionMenu, Entry, Tk, Button
# change the state of the Entry widget
def change_state(state='normal'):
E1.config(state=state)
def main():
print("test")
# callback function triggered by selecting from OptionMenu widget
def callback(*args):
if var.get() == 'no':
change_state(state='disable')
elif var.get() == 'yes':
change_state(state='normal')
root = Tk() #create a TK root window
root.title("Lunch and Learn") #Title of the window
L1 = Label(root, text="Label 1").grid(row=0, column=0, padx=30, pady=(20, 5))
L2 = Label(root, text="Label 2").grid(row=1, column=0, pady=5)
var = StringVar()
E1 = Entry(root, bd=3)
E1.grid(row=0, column=1)
D1 = OptionMenu(root, var, "yes", "no", command=callback)
D1.grid(row=1, column=1)
B2 = Button(text = "Submit", command=main).grid(row=4, column=2)
root.mainloop()

tkinter user input widget to xlsx

How do I write user input from tkinter entry widget to xlsx?
Should I be using a different module?
from tkinter import *
import xlsxwriter
def output():
c = Toplevel(root)
c.title =("Main")
c.geometry =('')
e= Entry(c, width=20).grid(row=0, column=1, sticky=W, padx=10)
l=Label(c, text="Current Value").grid(row = 0, column=0, sticky=W, padx=10)
e2 = Entry(c, width=20).grid(row=1, column=1, sticky=W, padx=10)
l2= Label(c, text="New Value").grid(row = 1, column=0, sticky=W, padx=10)
b=Button(c, text="Submit",command= write_to_xlsx).grid(row= 1, column=2, sticky=E, padx=10)
def write_to_xlsx():
workbook =xlsxwriter.Workbook('tkintertest18.xlsx')
worksheet = workbook.add_worksheet()
worksheet.write_string('C1', 'e2.get()')
workbook.close()
root = Tk()
root.title("Main Menu")
root.geometry('400x400+230+130')
Button(root, text="1", command=output).grid(row =0, column= 2)
root.mainloop()
You should almost always use a class when tkinter is involved. So here is a working prototype of your code above. There were multiple problems. One is that when you slap grid next to your widgets instead of putting them on a new line, grid returns None, not the object. Implementing the app as a class enables the other functions to access the GUI components (in this case self.e2). Another error was you had single-quoted the 'e2.get()' call, which is technically a string. So removing the quotes fixes that. There may have been other things...
import xlsxwriter
class XLwriter:
def __init__(self):
c = Toplevel(root)
c.title =("Main")
c.geometry =('')
self.e= Entry(c, width=20).grid(row=0, column=1, sticky=W, padx=10)
self.l=Label(c, text="Current Value").grid(row = 0, column=0, sticky=W, padx=10)
self.e2 = Entry(c, width=20)
self.e2.grid(row=1, column=1, sticky=W, padx=10)
self.l2= Label(c, text="New Value").grid(row = 1, column=0, sticky=W, padx=10)
self.b=Button(c, text="Submit",command=self.write_to_xlsx).grid(row= 1, column=2, sticky=E, padx=10)
def write_to_xlsx(self):
workbook =xlsxwriter.Workbook('tkintertest18.xlsx')
worksheet = workbook.add_worksheet()
worksheet.write_string('C1', self.e2.get())
workbook.close()
root = Tk()
root.title("Main Menu")
root.geometry('400x400+230+130')
app = XLwriter()
#Button(root, text="1", command=output).grid(row =0, column= 2)
root.mainloop()
Seeing that Ron already provided you with a class to perform this task I will respond with the non-class method of doing this to more closely reflect the current code you have.
Keep in mind that with xlsxwriter there is not a way to read from the spreadsheet so for the entry field you have that is labeled as "Current Value" you will need to use a different excel library to fill that field with data from the spreadsheet.
Make sure if you are going to interact with a widget that you do not use the geometry manager directly with the creation of the widget. This will return None to anything trying to interact with it. Instead on the next line after you have created the widget you can use the widget variable name and then your geometry manager of choice(grid(), pack(), place()). This will allow us to interact with the widget without the issue of None being returned by the geometry manager.
In order for you to be able to interact with e2 outside of the output() function you will need to assign e2 to the global namespace. You can do this by simply adding global e2 inside your output() function.
Note: The use of global is best avoided whenever possible this is one compelling reason to use a more Object Oriented Programing method (class) as the use of global is not needed when using class attributes.
from tkinter import *
import xlsxwriter
root = Tk()
root.title("Main Menu")
#root.geometry('400x400+230+130')
def output():
global e2
c = Toplevel(root)
c.title = ("Main")
e = Entry(c, width = 20)
e.grid(row = 0, column = 1, sticky = W, padx = 10)
l = Label(c, text = "Current Value")
l.grid(row = 0, column = 0, sticky = W, padx = 10)
e2 = Entry(c, width=20)
e2.grid(row = 1, column = 1, sticky = W, padx = 10)
l2 = Label(c, text = "New Value")
l2.grid(row = 1, column = 0, sticky = W, padx = 10)
b = Button(c, text = "Submit",command = write_to_xlsx)
b.grid(row = 1, column = 2, sticky = E, padx = 10)
def write_to_xlsx():
workbook = xlsxwriter.Workbook('tkintertest18.xlsx')
worksheet = workbook.add_worksheet()
worksheet.write_string('C1', e2.get())
workbook.close()
btn = Button(root, text = "1", command = output)
btn.grid(row = 0, column = 2)
root.mainloop()

How to create a sub frames with a specific layout?

I'm aiming to make a login program but the only part that confuses me is how to make the frames.I need 3 different frames but I neither know how to make a frame other the then like this:
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
and I can only make labels and widgets using that single mainframe. As far as making another one, it is beyond me. I need to know exactly place widets inside of each frame and even after creating frames I don't know how to place stuff on the grid. Would I go for the overall grid, or does something change after making the grid. I'm using the following layout for making the frame. Basically i'm hoping for a crash course in frames. Any information i've gathered doesn't make sense to me, even after I tried to put it into code.
I've got the coding part down just not the frame part.
#Import tkinter to make gui
from tkinter import *
from tkinter import ttk
import codecs
def login(*args
):
file = open("rot13.txt", "r")
lines = file.readlines()
uname = user.get()
pword = pw.get()
for i in lines:
x = i.split()
if codecs.encode(uname,'rot13') == x[0] and codecs.encode(pword,'rot13') == x[1]:
result.set("Successful")
break;
else:
result.set("Access Denied")
root = Tk()
root.title("Login")
#Configures column and row settings and sets padding
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
user = StringVar()
pw = StringVar()
result = StringVar()
user_entry = ttk.Entry(mainframe, width=20, textvariable=user)
user_entry.grid(column=2, row=1, sticky=(W, E))
pw_entry = ttk.Entry(mainframe, width=20, textvariable=pw)
pw_entry.grid(column=2, row=2, sticky=(W, E))
ttk.Label(mainframe, text="Username ").grid(column=1, row=1, sticky=W)
ttk.Label(mainframe, text="Password ").grid(column=1, row=2, sticky=W)
ttk.Label(mainframe, text="").grid(column=1, row=3, sticky=W)
ttk.Label(mainframe, text="Result").grid(column=1, row=4, sticky=W)
ttk.Label(mainframe, text="").grid(column=1, row=5, sticky=W)
ttk.Button(mainframe, text="Login", command=login).grid(column=3, row=6, sticky=W)
#Makes a spot to put in result
ttk.Label(mainframe, textvariable=result).grid(column=2, row=4, sticky=(W, E))
#Opens up with item selected and allows you to enter username without having to click it
user_entry.focus()
#Runs calculate if click enter
root.bind('<Return>', login)
root.mainloop()
I believe the key point that you are missing is that subframes of mainframe use mainframe as the parent and that widgets within subframes use the subframe as parent. Furthermore, you can then place the subframe within the mainframe and the subframe widgets within the subframe. You do not have to pass parents to .grid because each widget knows its parent. A simplified example:
from tkinter import *
root = Tk()
mainframe = Frame(root)
login = Frame(mainframe)
label = Label(login, text='label')
entry = Entry(login)
display = Frame(mainframe)
result = Label(display, text='display result')
mainframe.grid() # within root
login.grid(row=0, column=0) # within mainframe
label.grid(row=0, column=0) # within login
entry.grid(row=0, column=1) # within login
display.grid() # within mainfram
result.grid(row=2, column=0) # within display

Resources