Grid and Entry, Correct Alignment - python

How would I implement this in TkInter with Python?
Two numbers are input as the width and height, and are then saved to Mapwidth and Mapheight respectively. When the Confirm button is hit, the window closes.

More or less:
import tkinter as tk
# --- function ---
def on_confirm():
print('Mapwidth:', e1.get())
print('Mapheight:', e2.get())
root.destroy()
# --- main ---
root = tk.Tk()
l = tk.Label(root, text="Width")
l.grid(row=0, column=0)
e1 = tk.Entry(root)
e1.grid(row=0, column=1)
l = tk.Label(root, text="Height")
l.grid(row=1, column=0)
e2 = tk.Entry(root)
e2.grid(row=1, column=1)
b = tk.Button(root, text="Confirm", command=on_confirm)
b.grid(row=2, column=0, columnspan=2)
root.mainloop()

Related

how to update getting results from an entry box automatically?

I want to update getting results from an entry box in a way that when an integer enters, the equivalent rows of entry boxes appear below that. I have written the below code to make it work using a button. However, I want to make it happen automatically without a button as I entered the number, the rows update. I checked one way of doing that is using the after(). I placed after after() in the function and out of the function but it is not working.
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def update():
for i in range(1, n_para.get()+1):
entryX = Entry(root)
entryX.grid(row=i+1, column=0)
entryY = Entry(root)
entryY.grid(row=i+1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i+1, column=2)
root.after(100, update)
root.after(1, update)
button1 = Button(root, text="update", command=update)
button1.grid(row=1, column=0)
root.mainloop()
You should try using the <KeyRelease> event bind.
import tkinter as tk
def on_focus_out(event):
label.configure(text=inputtxt.get())
root = tk.Tk()
label = tk.Label(root)
label.pack()
inputtxt = tk.Entry()
inputtxt.pack()
root.bind("<KeyRelease>", on_focus_out)
root.mainloop()
This types the text entered in real-time.
Edited Code with OP's requirement:
from tkinter import *
root = Tk()
root.geometry("400x400")
n_para = IntVar()
label1 = Label(root, text="Numeric parameters")
label1.grid(row=0, column=0)
entry1 = Entry(root, textvariable=n_para)
entry1.grid(row=0, column=1)
def upd(event):
x = entry1.get()
if not x.isnumeric():
x = 0
for i in range(1, int(x)+1):
entryX = Entry(root)
entryX.grid(row=i+1, column=0)
entryY = Entry(root)
entryY.grid(row=i+1, column=1)
entryZ = Entry(root)
entryZ.grid(row=i+1, column=2)
# root.after(100, update)
root.bind("<KeyRelease>", upd)
# button1 = Button(root, text="update", command=update)
# button1.grid(row=1, column=0)
root.mainloop()

How can i make this text entry/frame as a whole disappear?

So I want to make this frame that I made disappear after the press of a button. Heres the code:
import tkinter as tk
root = tk.Tk()
root.geometry("150x50+680+350")
def FormSubmission():
global button_start
root.attributes("-fullscreen", True)
frame = tk.Frame(root)
tk.Label(frame, text="First Name:").grid(row=0)
entry1 = tk.Entry(frame)
entry1.grid(row=0, column=1)
tk.Label(frame, text="Last Name:").grid(row=1)
e2 = tk.Entry(frame)
e2.grid(row=1, column=1)
tk.Label(frame, text="Email:").grid(row=2)
e3 = tk.Entry(frame)
e3.grid(row=2, column=1)
tk.Label(frame, text="Date of Birth:").grid(row=3)
e4 = tk.Entry(frame)
e4.grid(row=3, column=1)
frame.pack(anchor='center', expand=True)
button_next = tk.Button(root, text = "Next", height = 2, width = 7, command = MainPage).pack()
button_start.place_forget()
def MainPage():
global FormSubmission
root.attributes("-fullscreen", True)
l1 = tk.Label(root, text = "Welcome Back," , font = ("Arial", 44)).pack()
button_start.place_forget() # You can also use `button_start.destroy()`
button_start = tk.Button(root, text="Start", height=3, width=20, command = FormSubmission)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()
So as you see I want to make the frame/function (FormSubmission) for the entry field disappear after pressing the next button after in the function (MainPage).
You can use pack_forget
Every geometry manager(pack, grid, place) has its own ..._forget
I've re-edit your snippet just for the use case you wished for.
Anyway I think you should re-design your app.
import tkinter as tk
root = tk.Tk()
root.geometry("150x50+680+350")
def FormSubmission():
global button_start
root.attributes("-fullscreen", True)
frame = tk.Frame(root)
tk.Label(frame, text="First Name:").grid(row=0)
entry1 = tk.Entry(frame)
entry1.grid(row=0, column=1)
tk.Label(frame, text="Last Name:").grid(row=1)
e2 = tk.Entry(frame)
e2.grid(row=1, column=1)
tk.Label(frame, text="Email:").grid(row=2)
e3 = tk.Entry(frame)
e3.grid(row=2, column=1)
tk.Label(frame, text="Date of Birth:").grid(row=3)
e4 = tk.Entry(frame)
e4.grid(row=3, column=1)
frame.pack(anchor='center', expand=True)
button_next = tk.Button(root, text = "Next", height = 2, width = 7, command = lambda: MainPage(frame)).pack()
button_start.place_forget()
def MainPage(frame):
global FormSubmission
frame.pack_forget()
root.attributes("-fullscreen", True)
l1 = tk.Label(root, text = "Welcome Back," , font = ("Arial", 44)).pack()
button_start.place_forget() # You can also use `button_start.destroy()`
button_start = tk.Button(root, text="Start", height=3, width=20, command = FormSubmission)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()

why is .grid giving me an error when I am trying to move my button

import time
import tkinter as tk
from tkinter import scrolledtext
win = tk.Tk()
win.title("My First Game")
win.configure(bg="black")
win.geometry("640x400")
label = tk.Label(win, text="test", fg="red", bg="black").pack()
canvas1 = tk.Canvas(win, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(win, font="Helvetica 10")
canvas1.create_window(65, 10, window=entry1)
entry1.insert(0, "Type here")
def shortcut():
Shortcut = tk.Label(win, fg="red", bg="black", text="test2")
Shortcut.pack()
button1 = tk.Button(win, text="Enter", fg="red", bg="black", command=shortcut)
button1.pack()
exit_button = tk.Button(win, text="Quit", padx=4, pady=2, bg="black", fg="red", command=quit)
exit_button.pack()
exit_button.grid(row=0, column=2)
win.mainloop()
Why is this giving me an error? I tried in a separate project with just a black screen and the button and it worked fine. But when I put it in the code above it doesn't work
line 42, in <module> exit_button.grid(row=0, column=2)
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
As #10Rep mentioned in comment - you can remove grid() to resolve problem with error.
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.pack()
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.pack()
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
button1 = tk.Button(win, text="Enter", command=shortcut)
button1.pack()
exit_button = tk.Button(win, text="Quit", command=win.destroy)
exit_button.pack()
win.mainloop()
But I expect that you used grid() to organize two buttons in one line.
Problem is that you can't mix pack() and grid() in one window/frame and I see two solutions:
First is to use only grid() to organize all widgets
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.grid(row=3, column=0, columnspan=2)
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.grid(row=0, column=0, columnspan=2)
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.grid(row=1, column=0, columnspan=2)
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
button1 = tk.Button(win, text="Enter", command=shortcut)
button1.grid(row=2, column=0)
exit_button = tk.Button(win, text="Quit", command=win.destroy)
exit_button.grid(row=2, column=1)
win.mainloop()
Second is to put Frame (using pack()) and put buttons inside this frame using grid()
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.pack()
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.pack()
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
# - frame with grid -
f = tk.Frame(win)
f.pack()
button1 = tk.Button(f, text="Enter", command=shortcut)
button1.grid(row=0, column=0)
exit_button = tk.Button(f, text="Quit", command=win.destroy)
exit_button.grid(row=0, column=1)
# -
win.mainloop()
or using pack(side=...)
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.pack()
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.pack()
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
# - frame with pack(side=...) -
f = tk.Frame(win)
f.pack()
button1 = tk.Button(f, text="Enter", command=shortcut)
button1.pack(side='left')
exit_button = tk.Button(f, text="Quit", command=win.destroy)
exit_button.pack(side='left')
# -
win.mainloop()

How to print the items in a tkinter window?

I have this code:
root= tk.Tk()
button1 = tk.Button(root, text='Button', command=lambda:print("Click"))
button1.grid(row=1, column=1)
Label = tk.Label(root, text="Text")
Label.grid(row=1, column=2)
root.mainloop()
What I want to get:
Button:(1, 1), Label:(1, 2)
How can I print the items and their destinations in root?
If you just want to get the information about grid, use grid_info() could get the info about the widget.To get all the widgets on root, just use root.winfo_children().
import tkinter as tk
root = tk.Tk()
button1 = tk.Button(root, text='Button', command=lambda:print("Click"))
button1.grid(row=1, column=1)
Label = tk.Label(root, text="Text")
Label.grid(row=1, column=2)
for widget in root.winfo_children():
print(f"{widget.widgetName}:({ widget.grid_info()['row']}, {widget.grid_info()['column']})")
root.mainloop()
Result:
button:(1, 1)
label:(1, 2)
Would this solve it? What you do is create a function that generates a label in root and then give it to the command argument of your button.
import tkinter as tk
root= tk.Tk()
def x():
y = tk.Label(root, text = "Click")
y.grid(row = 2, column = 1)
button1 = tk.Button(root, text='Button', command=x)
button1.grid(row=1, column=1)
Label = tk.Label(root, text="Text")
Label.grid(row = 2, column = 1)
root.mainloop()

How can I remove items on a Tkinter window?

I am trying to clear the items on the window without closing the root window just the items visible.While everything is deleted Some of the labels are still left.I created a button "close" to remove the items.My code is as below;
from tkinter import*
root = Tk()
root.geometry("480x480")
# Node
myLabel1 = Label(root, text=f'Node')
myLabel1.grid(row=0, column=0)
rows = [] # show the input entry boxes
for i in range(6):
# name
entry = Entry(root, width=5, bd=5)
entry.grid(row=2+i, column=0)
# x
myLabel2 = Label(root, text=f'x{i}')
myLabel2.grid(row=2+i, column=1)
entry_x = Entry(root, width=5, bd=5)
entry_x.grid(row=2+i, column=2)
# y
myLabel3 = Label(root, text=f'y{i}')
myLabel3.grid(row=2+i, column=3)
entry_y = Entry(root, width=5, bd=5)
entry_y.grid(row=2+i, column=4)
# save current input row
rows.append((entry, entry_x, entry_y))
def close():
for name,ex,ey in rows:
name.destroy()
ex.destroy()
ey.destroy()
myLabel3.destroy()
myLabel2.destroy()
myLabel1.destroy()
myButton_close.destroy()
myButton_close = Button(root, text="close",padx = 10,pady = 10, command=close)
myButton_close.grid(row=8, column=6)
root.mainloop()
where could i be going wrong?
Create a Frame to hold the widgets and then you can destroy the frame to clear the window:
from tkinter import *
root = Tk()
root.geometry("480x480")
frame = Frame(root)
frame.pack(fill=BOTH, expand=1)
# Node
myLabel1 = Label(frame, text=f'Node')
myLabel1.grid(row=0, column=0)
rows = [] # store the input entry boxes
for i in range(6):
# name
entry = Entry(frame, width=5, bd=5)
entry.grid(row=2+i, column=0)
# x
myLabel2 = Label(frame, text=f'x{i}')
myLabel2.grid(row=2+i, column=1)
entry_x = Entry(frame, width=5, bd=5)
entry_x.grid(row=2+i, column=2)
# y
myLabel3 = Label(frame, text=f'y{i}')
myLabel3.grid(row=2+i, column=3)
entry_y = Entry(frame, width=5, bd=5)
entry_y.grid(row=2+i, column=4)
# save current input row
rows.append((entry, entry_x, entry_y))
def close():
frame.destroy()
myButton_close = Button(frame, text="close", padx=10, pady=10, command=close)
myButton_close.grid(row=8, column=6)
root.mainloop()
Grouping widgets into a frame make it easier to clear certain part of the window.
You create the labels in a loop but you are not saving any reference to the labels except for the last myLabel2/3. However you can ask a widget about its children, and then destroy them all:
def close():
for widget in root.winfo_children():
widget.destroy()

Categories