I'm trying to make this really simple GUI using tkinter and I'm using grid as a layout manager.
But when I place a certain button in column 2, it appears to the extreme left side of the window.
I just want to place the buttons exactly where I want in the window but that doesn't seem to work.
I don't know what I'm doing wrong exactly but here's the code and a screenshot.
from tkinter import *
class GUI:
#Initialize the application window
def __init__(self):
w = 520
h = 350
self.window = Tk()
ws = self.window.winfo_screenwidth()
hs = self.window.winfo_screenheight()
x = (ws/2) -(w/2)
y = (hs/2) -(h/2)
self.window.title("Excel file import")
self.window.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.window.configure(bg='#004A99')
self.window.resizable(False,False)
# self.logo = Image.open(LOGO)
# self.log = self.logo.resize((150,105),Image.ANTIALIAS)
# self.logo2 = ImageTk.PhotoImage(self.log)
# self.lbl1 = Label(self.window, image=self.logo2)
# self.lbl1.image = self.logo2
# self.lbl1.grid(row=4, column=0, ipadx=0, ipady=0, pady=0, padx=0)
self.homeDirectory = r'C:/Users/Shtlrs/Desktop/Clients folder/'
self.cfgFile = self.homeDirectory + r'cfg.ini'
#Add client button
self.addClientBtn = Button(self.window, text="Add new client", bg='#1b98e0', fg="white",
width=20, height=1)
self.addClientBtn.grid(row=2, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.addClientBtn.bind("<ButtonRelease-1>",self.addNewClient)
#Select client button
self.selectClientBtn = Button(self.window, text="Select existing client", bg='#1b98e0', fg="white",
width=20, height=1)
self.selectClientBtn.grid(row=3, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.selectClientBtn.bind("<ButtonRelease-1>",self.selectClient)
# Delete client button
self.deleteClientBtn = Button(self.window, text="Delete existing client", bg='red', fg="white",
width=20, height=1)
self.deleteClientBtn.grid(row=4, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.deleteClientBtn.bind("<ButtonRelease-1>",self.deleteClient)
#Cients dropdown ( appears next to "select existing clients")
# clients = ["Medtronic","Ancora","Momo"]
# self.clientsDropDown = ttk.Combobox(self.window,values=clients)
# self.clientsDropDown.grid(row=3,column=1, ipadx=5,ipady=5,pady=5,padx=5)
# self.clientsDropDown.current(0)
self.restart = Button(self.window, text="Restart", bg='#1b98e0', fg="white",
width=20, height=1)
self.restart.grid(row=5, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.restart.bind("<ButtonRelease-1>", self.restartAPP)
self.window.mainloop()
The code lacks a lot of other functions of course (For the bindings)
But when I run this I get:
Buttons appear in the wrong column using tkinter's grid layout manager
Actually,it is the right position.Due to the first column has no widget,so it seems it is in the "wrong" column.
You can create a frame,and put all of your buttons in it.And use .pack(anchor=Center) or .pack(anchor="center") to make the frame in the center.Also,you need to set the bg attribute of Frame to make sure they have the same color.
Followed by your code,a minimal example code is here:
from tkinter import *
class GUI:
#Initialize the application window
def __init__(self):
w = 520
h = 350
self.window = Tk()
ws = self.window.winfo_screenwidth()
hs = self.window.winfo_screenheight()
x = (ws/2) -(w/2)
y = (hs/2) -(h/2)
self.window.title("Excel file import")
self.window.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.window.configure(bg='#004A99')
self.window.resizable(False,False)
self.buttonFrame = Frame(self.window,bg="#004A99") # create a new frame
self.buttonFrame.pack(anchor=CENTER) # make it center
# self.logo = Image.open(LOGO)
# self.log = self.logo.resize((150,105),Image.ANTIALIAS)
# self.logo2 = ImageTk.PhotoImage(self.log)
# self.lbl1 = Label(self.window, image=self.logo2)
# self.lbl1.image = self.logo2
# self.lbl1.grid(row=4, column=0, ipadx=0, ipady=0, pady=0, padx=0)
self.homeDirectory = r'C:/Users/Shtlrs/Desktop/Clients folder/'
self.cfgFile = self.homeDirectory + r'cfg.ini'
#Add client button
self.addClientBtn = Button(self.buttonFrame, text="Add new client", bg='#1b98e0', fg="white",width=20, height=1) # put your button in the frame.
self.addClientBtn.grid(row=2, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.addClientBtn.bind("<ButtonRelease-1>",self.addNewClient)
#Select client button
self.selectClientBtn = Button(self.buttonFrame, text="Select existing client", bg='#1b98e0', fg="white",width=20, height=1) # put your button in the frame.
self.selectClientBtn.grid(row=3, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.selectClientBtn.bind("<ButtonRelease-1>",self.selectClient)
# Delete client button
self.deleteClientBtn = Button(self.buttonFrame, text="Delete existing client", bg='red', fg="white",width=20, height=1) # put your button in the frame.
self.deleteClientBtn.grid(row=4, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.deleteClientBtn.bind("<ButtonRelease-1>",self.deleteClient)
#Cients dropdown ( appears next to "select existing clients")
# clients = ["Medtronic","Ancora","Momo"]
# self.clientsDropDown = ttk.Combobox(self.buttonFrame,values=clients) # put it in the frame.
# self.clientsDropDown.grid(row=3,column=1, ipadx=5,ipady=5,pady=5,padx=5)
# self.clientsDropDown.current(0)
self.restart = Button(self.buttonFrame, text="Restart", bg='#1b98e0', fg="white",
width=20, height=1)
self.restart.grid(row=5, column=2, ipadx=5, ipady=5, pady=5, padx=5)
self.restart.bind("<ButtonRelease-1>", self.restartAPP)
self.window.mainloop()
#You need to revise all the functions below.
def addNewClient(self):
pass
def selectClient(self):
pass
def deleteClient(self):
pass
def restartAPP(self):
pass
start = GUI()
Now it is:
Related
Since some days I'll try to align these two items inside a Tkinter frame:
The pink part should be on the left and the green button on the right. With HtmlDivs and CSS a question of seconds, with TKinter a pain in the ...
Here is my python code:
import tkinter as tk
root = tk.Tk()
root.geometry("400x200")
buttons = tk.Frame(root)
buttons.pack(side="top", expand=True, fill='both')
label = tk.Label(buttons, text="Hello, world", anchor='w', background='pink')
b2 = tk.Button(buttons, text="EXIT", background='green')
label.grid(row=0, column=1, sticky='w', ipadx = '20', padx = '20')
b2.grid(row=0, column=3, sticky='e', ipadx = '20', padx = '20')
root.mainloop()
The final app will be running fullscreen on a 7" touch display.
The simplest solution is to use pack instead of grid, since you only have a single row of widgets inside of buttons. pack's strength is arranging things in a single row or a single column.
Just remove these two lines:
label.grid(row=0, column=1, sticky='w', ipadx = '20', padx = '20')
b2.grid(row=0, column=3, sticky='e', ipadx = '20', padx = '20')
... and replace them with this:
label.pack(side='left')
b2.pack(side='right')
Also, since you appear to be creating a toolbar, you want to leave expand as False and set fill to just "x", otherwise the toolbar will expand to fill the entire window:
buttons.pack(side="top", expand=False, fill='x')
Thx for your tips,
this is just a testcode to update my maincode.
Its not good to mix .pack and .grid, right ? If i do, the script crashes completely,
so ill have to re-do my mainscript i think.
This is what i need:
row: 1/2: label (it will be a real time clock) left 2/2: exit button (exit fullscreen) right
row: 1/3: image (weather), 2/3: weather data (label), 3/3: calendar
row: 4 buttons: 1. lightoff 2. light25%, 3.light50% 4.light100&
Thats it basically all is working, it just need to align it (im a coding hero g)
Since i have the frame from the code above, i thought i can easily add 2. & 3. row with another frames, but that does not seem to work ??
Preview:
https://i.stack.imgur.com/KzoqV.png
My (main)Code so far
root = Tk()
root.title('Model Definition')
root.config(background = "deepskyblue4")
root.attributes('-fullscreen',True)
root.bind('<Escape>',lambda e: root.destroy())
def currenttime():
string = strftime("%A, %d.%B.%Y %H:%M:%S")
lbl.config(text = string, background = 'deepskyblue4', fg='white', font=("colibri", 30))
lbl.after(1000, currenttime)
def light400():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 401'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light425():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 425'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light450():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 450'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light475():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 500'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
# Main frames
top_frame = Frame(root, bg='deepskyblue4', width=450, height=90, pady=3)
center = Frame(root, bg='deepskyblue2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root, bg='deepskyblue4', width=450, height=20, pady=3)
btm_frame2 = Frame(root, bg='deepskyblue4', width=450, height=60, pady=3)
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
top_frame.grid(row=0, sticky="e", padx=(10, 0))
center.grid(row=1, sticky="nsew", pady=(10, 50))
btm_frame.grid(row=3, sticky="ew")
btm_frame2.grid(row=4, sticky="ew", padx=(10, 50))
# create the widgets for the top frame
lbl = Label(top_frame, background = 'deepskyblue4', anchor=W, justify=LEFT)
lbl.pack()
currenttime()
actionbutton = Button(top_frame, text="X", width=5, height=2, bg="deepskyblue4", fg="white", command=root.destroy)
hdr_left = Frame(top_frame, bg='deepskyblue4', width=100, height=190)
hdr_right = Frame(top_frame, bg='deepskyblue4', width=400, height=190, padx=3, pady=3)
# layout the widgets in the top frame
lbl.grid(row=0, column=1, sticky="w")
actionbutton.grid(row=0, column=2, sticky="e")
# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)
ctr_left = Frame(center, bg='deepskyblue2', width=100, height=190)
ctr_mid = Frame(center, bg='deepskyblue2', width=150, height=190, padx=3, pady=3)
ctr_right = Frame(center, bg='deepskyblue2', width=400, height=190, padx=3, pady=3)
ctr_left.grid(row=0, column=0, sticky="ns")
ctr_mid.grid(row=0, column=1, sticky="nsew")
ctr_right.grid(row=0, column=2, sticky="ns")
path = "icons/rain.png"
img = ImageTk.PhotoImage(Image.open(path))
panel = Label(ctr_left, image = img, bg="deepskyblue2")
panel.grid(row=0, columnspan=3)
#imgag = panel.pack(top_frame)
#CENTER ctr_mid
if x["cod"] != "404":
y = x["main"]
y2 = x["wind"]
currenttemp = y["temp"]
currentpressure = y["pressure"]
currenthumidiy = y["humidity"]
z = x["weather"]
weather_description = z[0]["description"]
currentwind = y2["speed"]
label1 = Label(ctr_mid,text='Karlsruhe', font = ('calibri', 30), background = 'deepskyblue2')
label2 = Label(ctr_mid,text='Temperatur: '+str(round(currenttemp-272.15))+' °C', font = ('calibri', 20), background = 'deepskyblue2')
label3 = Label(ctr_mid,text='Beschreibung: '+str(weather_description),font = ('calibri', 20), background = 'deepskyblue2')
label4 = Label(ctr_mid,text='Druck: '+str(currentpressure)+' hPa', font = ('calibri', 20), background = 'deepskyblue2')
label5 = Label(ctr_mid,text='Feuchtigkeit: '+str(currenthumidiy)+' %',font = ('calibri', 20), background = 'deepskyblue2')
label6 = Label(ctr_mid,text='Wind: '+str(currentwind)+' m/Sek',font = ('calibri', 20), background = 'deepskyblue2')
label1.grid(row=0, column=0, sticky="nw")
label2.grid(row=1, column=0, sticky="nw")
label3.grid(row=2, column=0, sticky="nw")
label4.grid(row=3, column=0, sticky="nw")
label5.grid(row=4, column=0, sticky="nw")
label6.grid(row=5, column=0, sticky="nw")
# btm_frame2 widgets
licht = Label(btm_frame2, text='Licht:', width=5, height=1, bg="deepskyblue4", fg='white', font=("colibri", 20))
button = Button(btm_frame2, command=light400, text="AUS", width=5, height=1, bg="deepskyblue2", fg="white")
button2 = Button(btm_frame2, text="25 %", command=light425, width=5, height=1, bg="deepskyblue2", fg="white")
button3 = Button(btm_frame2, text="50%", command=light450, width=5, height=1, bg="deepskyblue2", fg="white")
button4 = Button(btm_frame2, text="100%", command=light475, width=5, height=1, bg="deepskyblue2", fg="white")
licht.grid(row=0, column=0, sticky="nw")
button.grid(row=0, column=1, sticky="nw")
button2.grid(row=0, column=2, sticky="nw")
button3.grid(row=0, column=3, sticky="nw")
button4.grid(row=0, column=4, sticky="nw")
actionbutton.grid(row=0, column=6, sticky="nw")
root.mainloop()
I have a window with two parts. One part is to do some settings. I want to hide it until the user press a setting button. is it possible to hide a part of the frame that contains many widgets?
I have seen many examples to hide a widget in tkinter (eg. pack_forget and grid_forget). In my case, I am trying to hide a part of the frame through a button press (that contains more than one widgets). Any suggestions please
I can't use more than one frames because of some issues.
import tkinter as tk
def startFn():
pass
#fn body
def stopFn():
pass
#fn body
def FnToShow():
pass
#fn body ???
def FnToHide():
pass
#fn body ???
root = tk.Tk()
root.geometry('600x400')
#two containers like this.
#trying to hide container_2 untill the user press settingBtn
container_1 = tk.Frame(root, borderwidth=2, relief="solid")
container_2 = tk.Frame(root, borderwidth=2, relief="solid")
startBtn = tk.Button(container_1, text = "Start", command =startFn)
startBtn.grid(row=4, column=4)
stopBtn = tk.Button(container_1, text = "Stop", command= stopFn)
stopBtn.grid(row=5, column=4)
settingBtn = tk.Button(container_1, text = "Settings", command= FnToShow)
settingBtn.grid(row=6, column=4)
setting_1 = tk.Label(container_2, text = "Setting-1", fg='#000000')
setting_1.grid(row=3, column=10)
setting_2 = tk.Label(container_2, text = "Setting-2", fg='#000000')
setting_2.grid(row=4, column=10)
closeSettingBtn = tk.Button(container_2, text = "close Settings", command= FnToHide)
closeSettingBtn.grid(row=5, column=10)
container_1.pack(side="left", expand=True, fill="x", padx=1, pady=1)
container_2.pack(side="right",expand=True, fill="x", padx=1, pady=1)
root.mainloop()
You could show/hide the entire container_2 using the functions FnToShow and FnToHide:
something like this:
import tkinter as tk
def startFn():
pass
def stopFn():
pass
def FnToShow():
container_2.pack(side="right",expand=True, fill="x", padx=1, pady=1)
def FnToHide():
container_2.pack_forget()
root = tk.Tk()
root.geometry('600x400')
container_1 = tk.Frame(root, borderwidth=2, relief="solid")
container_2 = tk.Frame(root, borderwidth=2, relief="solid")
startBtn = tk.Button(container_1, text="Start", command =startFn)
startBtn.grid(row=4, column=4)
stopBtn = tk.Button(container_1, text="Stop", command= stopFn)
stopBtn.grid(row=5, column=4)
settingBtn = tk.Button(container_1, text="Settings", command= FnToShow)
settingBtn.grid(row=6, column=4)
setting_1 = tk.Label(container_2, text="Setting-1", fg='#000000')
setting_1.grid(row=3, column=10)
setting_2 = tk.Label(container_2, text="Setting-2", fg='#000000')
setting_2.grid(row=4, column=10)
closeSettingBtn = tk.Button(container_2, text="close Settings", command= FnToHide)
closeSettingBtn.grid(row=5, column=10)
container_1.pack(side="left", expand=True, fill="x", padx=1, pady=1)
root.mainloop()
What I want the frame to do is that when I click on the 'clear' button, the frame is cleaned but it does not and when I enter a string that is not valid and then a valid one, it shows traces of the past and past action. I already tried changing the Label.grid () by a Label.pack (), but it is worse since the 'animation' looks like a stack without removing any element when the 'clear' button is pressed
This is basically what would make it change
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
frame.config(bd=1, relief=SUNKEN)
frame.update()
status = Label(frame)
status.grid(row=0, column=0, sticky=NSEW)
def statusVal(value):
if not value == 0:
status = Label(frame, background="#ff4242", fg="#262626", text="Cadena invalida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#ff4242")
frame.update()
else:
status = Label(frame, background="#56ed42", fg="#262626", text="Cadena valida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#56ed42")
frame.update()
#Test
def validation():
capture = area.get()
if capture == '1':
return statusVal(0)
else:
return statusVal(1)
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()
See if this works better. The main change was to have the status Label always exist and hide or unhide it as desired — instead of creating a new one every time the validation() function was called. I also removed the code that was explicitly updating the frame which isn't necessary.
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
status.grid_remove() # Hide. but remember grid options.
def statusVal(value):
if not value == 0:
status.config(background="#ff4242", fg="#262626", text="Cadena invalida",
anchor="center")
status.grid() # Unhide
else:
status.config(background="#56ed42", fg="#262626", text="Cadena valida",
anchor="center")
status.grid() # Unhide
#Test
def validation():
capture = area.get()
if capture == '1':
statusVal(0)
else:
statusVal(1)
# Main
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
# Initialize status Label.
status = Label(frame, anchor="center")
status.grid(row=0, column=0)
status.grid_remove() # Hide it.
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()
I have reviewed the documentation on rowconfugre and columnconfigure, and I just do not quite understand how to get it working properly. With the following code, how can I get the 'src_entry' Entry box directly against the 'src' Checkbutton, regardless of what other widget is in column 1? Essentially, I need the size of the column to form to the width of whatever widget is in that space on the grid.
Thanks,
from tkinter import *
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent, background="white")
self.parent = parent
self.parent.title("TCPDUMP Creator")
self.centerWindow()
self.pack(fill=BOTH, expand=1)
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Exit", command=self.quit)
menubar.add_cascade(label="File", menu=fileMenu)
self.columnconfigure(2, weight=5)
int_lbl = Label(self, text="Interface")
int_lbl.grid(row=1, column=0, sticky=W+E)
self.int_entry = Entry(self, width=15)
self.int_entry.grid(row=1, column=1)
self.anyInt = BooleanVar()
Checkbutton(self, text="Any", variable = self.anyInt).grid(row=1, column=2)
int_lbl = Label(self, text="")
int_lbl.grid(row=2, column=0, columnspan=99, sticky=W+E)
self.notSrc = BooleanVar()
Checkbutton(self, text = "Not--", variable = self.notSrc).grid(row=3, column=0, sticky=W+E)
self.srcIP = BooleanVar()
Checkbutton(self, text="Src", variable = self.srcIP).grid(row=3, column=1)
src_entry = Entry(self, width=15)
src_entry.grid(row=3, column=2)
self.AndOr = StringVar()
self.AndOr.set(None)
Radiobutton(self, text = "And", variable = self.AndOr, value = "And").grid(row=3, column=3, pady=5, padx=2, sticky=E)
Radiobutton(self, text = "Or", variable = self.AndOr, value = "Or").grid(row=3, column=4, pady=5, padx=10, sticky=W)
self.notDst = BooleanVar()
Checkbutton(self, text = "Not--", variable = self.notDst).grid(row=3, column=5, sticky=W+E)
self.dstIP = BooleanVar()
Checkbutton(self, text="Dst", variable = self.dstIP).grid(row=3,column=6, sticky=E, padx=0)
dst_entry = Entry(self, width=15)
dst_entry.grid(row=3, column=7)
int_lbl = Label(self, text="")
int_lbl.grid(row=4, column=0, columnspan=99, sticky=W+E)
self.srcordst = StringVar()
self.srcordst.set(None)
Radiobutton(self, text = "And", variable = self.srcordst, value = "And").grid(row=4, column=1, pady=5, padx=2, sticky=E)
Radiobutton(self, text = "Or", variable = self.srcordst, value = "Or").grid(row=4, column=2, pady=5, padx=10, sticky=W)
def centerWindow(self):
w = 600
h = 300
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw - w)/2
y = (sh - h)/2.7
self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))
def main():
root = Tk()
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
The best way to do layouts is to break your UI into sections, and then layout each section independently.The reason you're having difficulty is that you're trying to force everything into a single grid, but you don't have items that naturally fit into a grid. You can make it work by using lots of invisible columns and clever use of columnspan, but there are easier ways.
In this specific case, pack and a few intermediate frames is a better solution in my opinion.
From what I see, your UI is made up of four areas:
A row that has an entry for int_entry and a checkbutton
A row that has several checkboxes and radiobuttons, along with an entry
A row with an 'And' and 'Or' radiobutton
A big blank area
The way I would do it is create four frames, one for each area:
frame1 = Frame(self, ...)
frame2 = Frame(self, ...)
frame3 = Frame(self, ...)
frame4 = Frame(self, ...)
You can then use pack to stack those frames horizontally. All of them fill their area in the horizontal direction, and the last frame takes up all of the rest of the data.
frame1.pack(side="top", fill="x")
frame2.pack(side="top", fill="x")
frame3.pack(side="top", fill="x")
frame4.pack(side="top", fill="both", expand=True)
Now, you can add widgets to each frame with little concern for how they affect the rest of the display.
For example, the "Interface" label, the entry and the "Any" checkbutton can go in frame1. pack makes for a sensible choice since you want these aligned to the left of the area (I assume...).
int_lbl = Label(frame1, text="Interface")
self.int_entry = Entry(frame1, width=15)
any_cb = Checkbutton(frame1, text="Any", ...)
int_lbl.pack(side="left")
self.int_entry.pack(side="left")
any_cb.pack(side="left")
Do the same for the other frames. Within each frame you can choose to use pack or grid, as long as you consistently use pack or grid for every widget within the frame. pack is a very natural choice when you want all of your widgets aligned in one direction in the parent widget.
I've been following this website for a while. It is really helpful. So, thanks for all the useful tips.
I've been searching for this answer for the past two weeks without any success, so now I'm compelled to ask out of total frustration with my current obstacle.
How do you use StringVar as a list?
Basically, I was coding the following program for my wife. The code is pretty messy as it is my first program I've tried to code.
The idea was that I would take 3 variables; password, secret number and website and then do some work on them using if statements and lists to create a unique password.
First problem was that I couldn't restrict the character length of the entry widgets but in the end i solved that but i still want to limit the characters that can be input.
for instance in the website entry box, i want to allow only letters.
If I could convert StringVar to a list, I could do some work with messy if statements to allow only certain characters in each index but everythime i try it says that stringvars cant be used as a list.
I need them as a list to limit the type of characters that can be entered and also so that i can do work on the variables to get the final output.
CODE:
from Tkinter import *
import Tkinter
from PIL import Image, ImageTk
import os
Title= ("Helvetica", 20, "bold", "underline")
Heading= ("Courier", 20, "bold")
Body= ("Courier", 15)
Body1= ("Courier", 15, "bold")
notice= ("Courier", 10)
Body2= ("Courier", 15, "bold", "underline")
root = Tk()
root.title("Koala Series: Encrypter")
root.configure(background="#ffefd5")
root.geometry('{}x{}'.format(510, 600))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1) # not needed, this is the default behavior
root.rowconfigure(1, weight=1)
root.rowconfigure(2, weight=1)
website = StringVar()
Titlemsg = Label(root, text="Koala Encrypter", font=Title, bg="#00FA9A", relief=RAISED,)
Titlemsg.grid( row=7, pady=25, sticky=N+S+E+W)
img1 = ImageTk.PhotoImage(Image.open("koala.jpeg"))
startpic = Label(root, image = img1, relief=RIDGE )
startpic.grid( row=10,pady=25, )
Head = Label(root,anchor=CENTER,text="Welcome to the Koala Encrypter \n\n A Koala series tool that allows you\n\n to Encrypt your passwords \n\n Click \'Start Encrypting\' to continue \n\n", font=Body, bg="#ffefd5", relief=RAISED,)
Head.grid( row=14, pady=25, columnspan=2, sticky=N+S+E+W)
web = Label(root, text="WEBSITE: ", font=Body, bg="#ffefd5", justify=CENTER,)
#website.set("Enter your website here")
entry = Entry(root,textvariable=website , justify=CENTER,relief=SUNKEN,cursor="pencil", takefocus=True )
Notice1 = Label( text="Please only insert the first 5 letters of the website!!",font=notice, bg="#ffefd5", fg="#0000ff",)
passw = Label(root, text="PASSWORD: ", font=Body, bg="#ffefd5", justify=CENTER)
passwordvar= StringVar()
entry1 = Entry(root, textvariable= passwordvar, justify=CENTER,relief=SUNKEN, cursor="pencil", takefocus=True )
Notice= Label(root, text="Your password must only be 5 characters long!!", font=notice, bg="#ffefd5", fg="#0000ff", justify=CENTER)
def callback(event):
if "<0>":
top = Toplevel(bg="#ffefd5")
top.title("Koala Encrypter")
popuptitle = Label(top, text="Your secret number must be between 1 and 9:", font=Body1, fg="red", bg="#ffefd5")
popuptitle.grid(row = 2,column=0, padx=5, pady = 50,sticky=N+S+E+W)
secret = Label(root, text="SECRET NUMBER: ", font=Body, bg="#ffefd5" , justify=CENTER,)
numbervar = StringVar()
entry2 = Entry(root, textvariable=numbervar , justify=CENTER,relief=SUNKEN,cursor="pencil", takefocus=True)
entry2.bind("<0>", callback)
Notice2 = Label(root, text="your secret number must be between 1 and 9!!!", font=notice, bg="#ffefd5", fg="#0000ff", justify=CENTER)
img = ImageTk.PhotoImage(Image.open("Koalalogo.jpg"))
panel = Label(root, image = img, relief=SUNKEN)
correct= Label(root, text="Check the below details \n\n Click \'yes\' if they are correct \n\n Click \'No\' to go back \n\n", font=Body1, bg="#ffefd5")
yourwebsite = Label(root, text="The Website is :", font=Body, bg="#ffefd5")#
website1 = Label(root, font=Body2, bg="#ffefd5",fg= "#00009C", textvariable = website)#
yourpassword = Label(root, text="Your Password is:", font=Body, bg="#ffefd5")
yournumber1= Label(root, font=Body2, bg="#ffefd5",textvariable = numbervar , fg= "#00009C", )
yourpassword1 = Label(root, font=Body2, bg="#ffefd5",textvariable = passwordvar , fg= "#00009C", )
yournumber= Label(root, text="Your Secret Number is:", font=Body, bg="#ffefd5")
def restart():
Titlemsg.grid_forget()
correct.grid_forget()
yourwebsite.grid_forget()
website1.grid_forget()
yourpassword.grid_forget()
yourpassword1.grid_forget()
yournumber.grid_forget()
yournumber1.grid_forget()
panel.grid_forget()
toolbar.grid_forget()
yes.grid_forget()
no.grid_forget()
entry.delete(0,END)
entry1.delete(0,END)
entry2.delete(0,END)
Titlemsg.grid( row=7, pady=25, sticky=N+S+E+W)
startpic.grid( row=10,pady=25, )
Head.grid( row=14, pady=25, columnspan=2, sticky=N+S+E+W)
toolbar.grid( row=21, )
end.grid(column =3, row=1, sticky=N+S+E+W)
begin.grid(column =2, row=1, sticky=N+S+E+W)
def start():
#entry.destroy()
#entry1.destroy()
#entry2.destroy()
toolbar.grid_forget()
Titlemsg.grid_forget()
begin.grid_forget()
Head.grid_forget()
startpic.grid_forget()
web.grid(row=3, column=0, sticky= W+E)
entry.grid( row=3, column=1, padx=50)
passw.grid(row=10, column=0)
Notice1.grid(row=4, sticky=N+S+E+W, columnspan=2)
entry1.grid(row=10, column=1)
Notice.grid(row=11,column=0, columnspan=2,)
secret.grid(row=13, column=0)
entry2.grid( row=13, column=1)
Notice2.grid( row=14,column=0, columnspan=2,)
panel.grid(row=20,columnspan=2, pady=70)
confirm.grid(column =1, row=1)
reset.grid(column =2, row=1)
end.grid(column =3, row=1)
toolbar.grid(row=21, column=0, columnspan=2)
Titlemsg.grid(row=0, column=0, columnspan=2, sticky=E+W)
def Reset():
entry.delete(0,END)
entry1.delete(0,END)
entry2.delete(0,END)
def clear_text():
#entry.destroy()
#entry1.destroy()
#entry2.destroy()
panel.grid_forget()
entry.grid_forget()
entry1.grid_forget()
entry2.grid_forget()
web.grid_forget()
Notice.grid_forget()
passw.grid_forget()
secret.grid_forget()
Notice1.grid_forget()
Notice2.grid_forget()
confirm.grid_forget()
reset.grid_forget()
toolbar.grid_forget()
Titlemsg.grid_forget()
Titlemsg.grid(row=0, column=0, columnspan=2, sticky=E+W)
correct.grid(row=1, column=0, columnspan=2, sticky=E+W)
yourwebsite.grid(row=2,column=0,sticky=E+W, pady=5)
website1.grid(row=2, column=1, padx=65,sticky=E+W, pady=5)
yourpassword.grid(row=4, column=0,sticky=E+W, pady=5)
yourpassword1.grid(row=4, column=1, padx=65,sticky=E+W, pady=5)
yournumber.grid(row=6, column=0,sticky=E+W, pady=5)
yournumber1.grid(row=6, column=1, padx=65,sticky=E+W, pady=5)
panel.grid(row=8, column=0, columnspan=2, pady=50)
toolbar.grid(row=10, column=0, columnspan=2)
yes.grid(column =1, row=1)
no.grid(column =2, row=1)
def popup():
top = Toplevel(bg="#ffefd5")
top.title("Koala Encrypter")
popuptitle = Label(top, text="Your password is:", font=Body1, fg="red", bg="#ffefd5")
popuptitle.grid(row = 2,column=0, padx=5, pady = 50,sticky=N+S+E+W)
pwd= Label(top, font=Body2, text="password", bg="#ffefd5", fg= "#00009C", ) #textvariable = newpassword ,
pwd.grid(row= 2, column=1,sticky=E+W,padx=15)
button = Button(top, text="OK", command=top.destroy, relief=RAISED )
button.grid(column =0,columnspan=2, row=4, sticky=N+S+E+W)
def helpmsg():
top = Toplevel(bg="#ffefd5")
top.title("Koala Encrypter")
popuptitle = Label(top, text="Koala series 1.0 - Koala Encrypter", font=Title, bg="#00FA9A", relief=RAISED,)
popuptitle.grid(row = 2,column=0, padx=5, pady = 50,sticky=N+S+E+W)
pwd= Label(top, font=Body, text="Free software to help you keep your acounts safe", bg="#ffefd5")
pwd.grid(row= 1,sticky=E+W,)
Titlems = Label(top, text="Koala Encrypter", font=Title, bg="#00FA9A", relief=RAISED,)
Titlems.grid( row=0, pady=25, sticky=N+S+E+W)
button = Button(top, text="OK", command=top.destroy, relief=RAISED )
button.grid(column =0,columnspan=2, row=4, sticky=N+S+E+W)
max_len = 5
def on_write(*args):
s = website.get()
if len(s) > max_len:
website.set(s[:max_len])
website.trace_variable("w", on_write)
max_len1 = 5
def on_write(*args):
s = passwordvar.get()
if len(s) > max_len1:
passwordvar.set(s[:max_len1])
passwordvar.trace_variable("w", on_write)
max_len2 = 1
def on_write(*args):
s = numbervar.get()
if len(s) > max_len2:
numbervar.set(s[:max_len2])
numbervar.trace_variable("w", on_write)
toolbar = Frame(root)
reset = Button(toolbar, text="Reset", width=6, command=Reset, cursor="cross", relief=RAISED, takefocus=True )
end = Button(toolbar, text="Quit" ,command=root.destroy, relief=RAISED, cursor="X_cursor", takefocus=True)
end.grid(column =3, row=1, sticky=N+S+E+W)
begin = Button(toolbar, text="Start Encrypting", command=start, relief=RAISED, cursor="star",takefocus=True )
begin.grid(column =2, row=1, sticky=N+S+E+W)
confirm = Button(toolbar, text="Next", command =clear_text, cursor="star", relief=RAISED,takefocus=True )
yes = Button(toolbar, text="Yes", command =popup, cursor="star", relief=RAISED,takefocus=True )
no = Button(toolbar, text="No", command =restart, cursor="pirate", relief=RAISED, takefocus=True )
toolbar.grid( row=21, )
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu)
menu.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="Restart", command=restart)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.destroy)
helpmenu = Menu(menu)
menu.add_cascade(label="Help", menu=helpmenu, )
helpmenu.add_command(label="About...", command=helpmsg)
app = root
root.mainloop()
# add functionality, fix validation
To restrict the type/number of characters that can be typed into an entry widget, you can use the entry validatecommand. Here is an example to allow only letters and another one to restrict the entry to 4 digits:
from tkinter import Tk, Entry, Label
def only_letters(action, char):
if action == "1":
# a character is inserted (deletion is 0) allow the insertion
# only if the inserted character char is a letter
return char.isalpha()
else:
# allow deletion
return True
def only_numbers_max_4(action, new_text):
if action == "1":
return new_text.isdigit() and len(new_text) <= 4
else:
return True
root = Tk()
# register validate commands
validate_letter = root.register(only_letters)
validate_nb = root.register(only_numbers_max_4)
Label(root, text="Only letters: ").grid(row=0, column=0)
e1 = Entry(root, validate="key", validatecommand=(validate_letter, '%d', '%S'))
# %d is the action code and %S the inserted/deleted character
e1.grid(row=0, column=1)
Label(root, text="Only numbers, at most 4: ").grid(row=1, column=0)
e2 = Entry(root, validate="key", validatecommand=(validate_nb, '%d', '%P'))
# %P is the new content of the entry after the modification
e2.grid(row=1, column=1)
root.mainloop()
For more details on entry validation, see http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html