import tkinter
from tkinter import *
root = Tk()
root.geometry("500x500")
root.title("Insert title")
root.configure(background='#CCCCFF')
label1 = Label(root, text = "Insert title", font = ("Rockwell", 12))
label2 = Label(root, text = "Name", font = ("Rockwell", 25))
label1.configure(background='#CCCCFF')
label2.configure(background = '#CCCCFF')
label1.grid(row = 8, column = 3)
root.mainloop()
Every time I change the settings for the grid manager for label2, the label always stays in the same place. How can I fix this?
If you're asking "why does my 'Insert title' label always appear in the upper left corner, even though it has large row and column values?", it's because totally empty rows and columns are squashed down to zero pixels, so the eighth row will appear to be the first row, if rows 1 through 7 don't have any widgets in them.
One possible workaround is to add placeholder widgets to each row and column that you don't want to collapse.
import tkinter
from tkinter import *
root = Tk()
root.geometry("500x500")
root.title("Insert title")
root.configure(background='#CCCCFF')
for i in range(10):
Frame(root, width=20, height=20, background='#CCCCFF').grid(row=0, column=i)
for j in range(10):
Frame(root, width=20, height=20, background='#CCCCFF').grid(column=0, row=j)
label1 = Label(root, text = "Insert title", font = ("Rockwell", 12))
label2 = Label(root, text = "Name", font = ("Rockwell", 25))
label1.configure(background='#CCCCFF')
label2.configure(background = '#CCCCFF')
label1.grid(row = 8, column = 3)
label2.grid(row = 9, column = 3)
root.mainloop()
if a row or column is completely empty, it's size will be zero. So even though you put something in row 8, rows zero through seven are non-existent. The same goes for the columns.
Related
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()
I have a little problem with tkinter Display:
The Black and white bar aren't pulled trough. Why not?
I declared the white bar in White Info Bar, and the Black Info Bar in Black Bar.
But they stop at the second Side Bar (Frame f4).
I want both upper bars to go trough the whole Window, but don't know how to do it.
Please give me some help.
A left a few unimportant things, like the fonts away.
Please forgive the mess.
My code:
And an Image (Display)
from tkinter import *
import tkinter.font as tkFont
import tkinter as tk
root = Tk()
root.geometry("200x100")
# White Info Bar
f2 = tk.Frame(root, background = "white", width = 1, height = 30)
f2.grid(row = 1, column = 0, sticky = "ew")
# Side Bars
f3 = tk.Frame(root, bg = "black", width = 1, height = 1)
f3.grid(row = 3, column = 0, sticky = "nsw")
root.grid_rowconfigure(3, weight = 1)
f4 = tk.Frame(root, bg = "black", width = 1, height = 1)
f4.grid(row = 3, column = 1, sticky = "nse")
root.grid_rowconfigure(3, weight = 1)
# Window
root.title("THE FRIDGER")
root.geometry("500x500")
# Black Bar
f1 = tk.Frame(root, background="black", width=1, height=45)
f1.grid(row=0, column=0, sticky="ew")
root.grid_columnconfigure(0, weight=1)
# Black Bar Content
fridge = Label(f1, text = "Fridge", fg = "white", bg = "black")
fridge.grid(column = 0, row = 0, pady = 4, padx = 4)
recipes = Label(f1, text = "Recipes", fg = "white", bg = "black")
recipes.grid(column = 1, row = 0, pady = 4, padx = 4)
# Entry
content = Label(f3, text = "Content:", fg = "white", bg = "black")
content.grid(column = 0, row = 2, sticky = W)
quest = Entry(f3, width = 36, bg = "white", fg = "black", relief = FLAT)
quest.grid(column = 0, row = 3, sticky = W)
content1 = Label(f4, text = "Content:", fg = "white", bg = "black")
content1.grid(column = 0, row = 2, sticky = W)
quest1 = Entry(f4, width = 36, bg = "white", fg = "black", relief = FLAT)
quest1.grid(column = 0, row = 3, sticky = W)
root.bind("<Return>", analyse)
root.mainloop()
You have lots of issues/misunderstandings.
assigning width and height to a Frame does nothing unless you also call propagate(0) on the Frame. You don't need to worry about doing that though cause, your app is based on weight and content.
using a Frame as a separator bar is noobish. Use a ttk.Separator instead. Make it thicker by adding ipady (if necessary ... or ipadx if vertical)
all of your stuff has terrible names that don't mean or reveal anything. To illustrate this, try to describe your code and take note of how much sense it does not make ~ "First I put the fridge and recipes in the f1, and separate it from the content with f2...". Now explain my refactor ~ "First I put 2 anonymous labels in a header Frame and follow it with a separator..". Names matter!
your sticky values are confused. You are attempting to consider the entire app with your sticky, but tkinter is just considering the cell each widget is in. For instance: sticky='nse' does not make the cell stick to the right side. It makes the widget IN THE CELL stick to the right side of the cell.
your header frame and separator are intended to span both of the columns below them, but you never told either to do that
you store references to every Label even though you will likely never change or remove any of those Labels
you double import tkinter AND use both syntax possibilities in your code. For instance: some of your stuff is tk.Label and some of it is just Label, but both of these return the same kind of Label. It's very sloppy.
rows and columns are not global. In other words, if you use row=2 IN a Frame, you don't have to start with row=3 FOR the next Frame. Similarly, if you put a Frame on row 3, you don't have to start it's children on row 4. Every Frame you create has it's own grid and it will always start with 0,0 indexes for it's children.
arguments for tkinter classes/methods can already become ridiculous in length. Doing this: var = val, var2 = val2, var3 = val3 is not helping. Also, writing the exact same arguments across multiple widgets is not efficient. Prepare your common arguments for use as kwargs.
you start your app by configuring the root, but then you configure it a little more later on, and then a little more even later on. Doing this is a recipe for problems/errors/useless code. This is evidenced by the fact that you configured the same row twice, and assigned geometry twice. If you are working on a widget (including root), finish it (as much as possible) before going on to the next widget. Sometimes this is not entirely possible (like when attaching scrollbars to things), but it is generally mostly possible.
You can glean the rest from this refactor of your code.
import tkinter as tk, tkinter.ttk as ttk
root = tk.Tk()
root.title("THE FRIDGER")
root.geometry("500x500")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(2, weight=1)
#prepared data
dflt = dict(fg="white", bg="black")
pads = dict(pady=4, padx=4)
#header frame
header = tk.Frame(root, bg="black")
header.grid(row=0, column=0, columnspan=2, sticky="nsew")
for i in range(2):
header.grid_columnconfigure(i, weight=1)
#header labels
tk.Label(header, text="Fridge", **dflt).grid(column=0, row=0, **pads)
tk.Label(header, text="Recipes", **dflt).grid(column=1, row=0, **pads)
#separator
s = ttk.Style()
s.configure('custom.TSeparator', background='white')
ttk.Separator(root, style='custom.TSeparator').grid(row=1, column=0, columnspan=2, sticky="ew")
#left side content
l_content = tk.Frame(root, bg="black")
l_content.grid(row=2, column=0, sticky="nsew")
tk.Label(l_content, text="Content:", **dflt).grid(column=0, row=0, sticky=tk.W)
l_query = tk.Entry(l_content, width=36, relief=tk.FLAT, **dflt)
l_query.grid(column=0, row=1, sticky=tk.W)
#right side content
r_content = tk.Frame(root, bg="black")
r_content.grid(row=2, column=1, sticky="nsew")
tk.Label(r_content, text="Content:", **dflt).grid(column=0, row=0, sticky=tk.W)
r_query = tk.Entry(r_content, width=36, relief=tk.FLAT, **dflt)
r_query.grid(column=0, row=1, sticky=tk.W)
#root.bind("<Return>", analyse)
root.mainloop()
I have a project on python I am working on.
I need to make a program which runs CSV, matplotlib and other modules.
I have encountered a problem I can't solve, saving new info through the tkinter to the original CSV file
Mainly the problem is the "save to db" function
My entire code is :
from tkinter import *
from tkinter.ttk import *
import pandas as pd
from tkinter import messagebox
root = Tk()
root.title('DYR')
root.minsize(700, 500) # the minimum size of the window
root.geometry('500x500') # in what resolution the window will open at
root.configure(bg='LightBlue1')
nameLabel = Label(root, text=' Company Name',font=("Arial Bold", 12))
nameLabel.grid(column=2, row=0)
nameInput = Entry(width=30)
nameInput.grid(column=3, row=0)
idLabel= Label(root, text = 'Client ID',font=("Arial Bold", 12))
idLabel.grid(column=2, row=1)
id_input = Entry(width=9)
id_input.grid(column= 3, row=1)
addresslabel= Label(root, text = "Company Address", font=("Arial Bold", 12))
addresslabel.grid(column= 2, row= 2)
addressinput = Entry (width= 50 )
addressinput.grid(column =3 , row = 2)
fieldlabel= Label(root, text= "Filed",font=("Arial Bold", 12))
fieldlabel.grid(column=2 , row =3)
fieldcomobx = Combobox (root)
fieldcomobx['values']= ("Choose field",'consulting','Medical','Gaming','Cyber')
fieldcomobx.current(0) #set the selected item
fieldans = fieldcomobx.get()
fieldcomobx.grid(column=3, row=3)
numberof = Label (root, text = "Number of employees", font=("Arial Bold", 12))
numberof.grid(column = 2 , row = 4)
numberin = Entry (width= 15)
numberin.grid(column = 3 , row= 4)
contactlabel=Label(root, text = "Contact", font=("Arial Bold", 12))
contactlabel.grid(column=2, row =5)
contactin = Entry (width = 15)
contactin.grid(column=3, row =5)
lastcall = Label (root, text = "Last call ",font=("Arial Bold", 12))
lastcall.grid(column = 2 , row = 6)
lastcallin = Entry (width = 15)
lastcallin.grid(column = 3 , row=6)
def cheker():#func to check if the client exsit
import pandas as pd
path = r"C:\Users\HP\PycharmProjects\untitled\Gmar\Gmar_Project.csv"
companyName = str(nameInput.get())
df = pd.read_csv(path)
result = df[df.Company == companyName]
if len(result) == 0:
messagebox.showinfo("Cheker", "Not exist, Good luck!")
else:
messagebox.showinfo("Cheker", "The client already exists in the data base!")
btn = Button(root,text="check existence",command= cheker)
btn.grid(column=4, row = 0)
def save_to_db(): #save the information to csv
path = r"C:\Users\HP\PycharmProjects\untitled\Gmar\Gmar_Project.csv"
newRow = [str(nameInput.get()), str(id_input.get()), str(addressinput.get()),str(fieldans), str(numberin .get()),str(contactin.get()),str(lastcallin.get())]
df = pd.read_csv(path)
df2 = pd.DataFrame(newRow).T
df2.columns = ['Company','client ID','address','field','Number of employees','contact','last call'] # df.columns
df = df.append(df2, ignore_index=True)
df.to_csv(path_or_buf=path, index_label=False, index=False)
endbtn = Button (root, text = "SAVE" ,command = save_to_db())
endbtn.grid(column =3, row=8)
root.mainloop()
The problem is that you are setting fieldans about a millisecond after you create the combobox. The user won't have had a chance to make a section.
A general rule of thumb in GUI development is that you should not fetch data until immediately before you need it.
You need to move fieldans = fieldcomobx.get() inside of save_to_db so that you get the value entered by the user rather than the default value.
You also have the problem that you're calling save_to_db immediately as the GUI starts rather than after the user has had a chance to enter any data.
You need to define endbtn like this:
endbtn = Button (root, text = "SAVE" ,command = save_to_db)
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()
By default, after making a tkinter button, it automatically puts the next one on the other line.
How do I stop this from happening?
I want to do something like this:
You must use one of the geometry managers for that:
here with grid:
import tkinter as tk
root = tk.Tk()
b1 = tk.Button(root, text='b1')
b2 = tk.Button(root, text='b2')
b1.grid(column=0, row=0) # grid dynamically divides the space in a grid
b2.grid(column=1, row=0) # and arranges widgets accordingly
root.mainloop()
there using pack:
import tkinter as tk
root = tk.Tk()
b1 = tk.Button(root, text='b1')
b2 = tk.Button(root, text='b2')
b1.pack(side=tk.LEFT) # pack starts packing widgets on the left
b2.pack(side=tk.LEFT) # and keeps packing them to the next place available on the left
root.mainloop()
The remaining geometry manager is place, but its use is sometimes complicated when resizing of the GUI occurs.
Simply use this to make the y coordinates the same and change the x coordinate:
from tkinter import *
root = Tk()
Button(root, text='Submit', width=10, bg='blue', fg='white',
command=database).place(x=70, y=130)
For the second button:
buttonSignIn = Button(root, text="Sign in", width=10, bg='black',
fg='white', command=new_winF).place(x=30, y=130)
I had the same problem once, and found this: two "simple" ways to move widgets around a GUI area, are
i) Using the ".grid" attribute (see example below):
MyButton_FilePath = Button(
master = gui,
text = 'Open',
command = funcion_openfile_findpath,
fg = 'Black', font = ('Arial bold',11)
)
MyButton_FilePath.grid(row = 0, column = 2, padx = 4, pady = 4)
ii) Or using the attribute ".place":
MyButton_FilePath = Button(
master = gui,
text = 'Open',
command = funcion_openfile_findpath,
fg = 'Black', font = ('Arial bold',11)
)
MyButton_FilePath.place(x=300, y=400)
Note that I have separated the "Button" object into two lines - as it is considered to be a better practice whenever placing/gridding widgets...
Hope I have helped.
Try both ways and see which one fits better your wishes! :)
Cheers, Marcos Moro, PhD