Tkinter grid not working - python

I want to create a window, and content all in center, but I don't know how should I do, please help me.
def about_window():
win_about = tk.Toplevel(win)
win_about.geometry("340x500")
win_about.title("About Us")
win_about.resizable(0,0)
win_about.iconbitmap(r'C:/Users/810810/Desktop/python/eslogo.ico')
frame = tk.Frame(win_about)
frame.grid(row=0, column=2)
img_png = tk.PhotoImage(file = 'est.gif')
label = tk.Label(frame, image = img_png)
label.img_png = img_png
label.grid(row=0, column=1)
Message = 'Version: 1.0'
mess = tk.Label(frame, text=Message)
mess.grid(row=1, column=0)

I've also had a lot of problems with tkinter grid and prefer to use tkinter place.
Below I edited your code to use place instead of grid. anchor refers to the anchor point of the object you are moving around, relx refers to the relative x position as a percentage of the frame it's in (.5 meaning halfway through the frame), and rely refers to the y position in the frame from 0-1.
import tkinter as tk
win_about = tk.Tk()
win_about.geometry("340x500")
win_about.title("About Us")
win_about.resizable(0,0)
label = tk.Label(win_about, text="img_png", fg="black")
label.place(anchor='center', relx =.5, rely=.3)
mess = tk.Label(win_about, text='Version: 1.0', font=12)
mess.place(anchor='center', relx=.5, rely=.7)
win_about.mainloop()

this should work (It worked on my ubuntu 16 with python 2.7)
it opens 2 windows ,is that wanted or unwanted ?
it displays an image in the center and your text below.
it works by adding " " strings, just like neeraj nair suggested. (he suggested placing anything to adjust layout.)
(# Elvis Fan: i know you use windows, but it should work for windows too.)
import Tkinter as tk
def about_window():
win_about = tk.Toplevel()
win_about.geometry("340x500")
win_about.title("About Us")
win_about.resizable(0,0)
frame = tk.Frame(win_about)
frame.grid(row=0, column=2)
for i in range(0,12):
Message = " "
mess = tk.Label(frame, text=Message)
mess.grid(row=i, column=0)
img_png = tk.PhotoImage(file = 'gbsnode.png')
label = tk.Label(frame, image = img_png)
label.img_png = img_png
label.grid(row=21, column=2)
Message = ' '
mess = tk.Label(frame, text=Message)
mess.grid(row=23, column=1)
Message = 'Version 1'
mess = tk.Label(frame, text=Message)
mess.grid(row=24, column=2)
frame.mainloop()
about_window()
while True:
pass

Related

How can I make two widgets on the same column have different widths in Tkinter?

I'm trying to find a way to format this tkinter GUI so that I can have widgets in the same column that are different widths. I want to do this so that each label doesn't have an unnecessary amount of white space on either side and can be directly next to its entry box. I've tried shrinking the column, but that obscures the prompt. There might also be another way that I'm not aware of that would format this in a visually appealing way. I am open to any suggestions.
This is what it currently looks like.
import tkinter as tk
responses = ['running', 'reading', 'programming', 'fishing']
prompt_2 = "At what time do you want to do each activity?"
root = tk.Tk()
root.geometry("335x200")
root.title("Schedule Maker")
prompt = tk.Label(
root,
text=prompt_2
)
button = tk.Button(
root,
text="ENTER",
width=10,
height=2
)
button.grid(row=len(responses)+1, column=0)
prompt.grid(row=0, column=0)
prompt['text'] = prompt_2
label0_list = []
label1_list = []
entry0_list = []
entry1_list = []
for w in range(len(responses)):
label0 = tk.Label(root, text=responses[w] + ":")
label0.grid(row=w+1, column=0)
label0_list.append(label0)
label1 = tk.Label(root, text='to')
label1.grid(row=w+1, column=2)
label1_list.append(label1)
entry0 = tk.Entry(root, width=6)
entry0.grid(row=w+1, column=1)
entry0_list.append(entry0)
entry1 = tk.Entry(root, width=6)
entry1.grid(row=w+1, column=3)
entry1_list.append(entry1)
root.mainloop()
Think of tk.Tk() as a rectangle of space where you can put in your content.
The content is managed by the geometry manager of your choice, like pack or grid.
Sometimes people call these rectangle of space container.
Frames are used to have a seperated area where you can organize the content, with different settings. So frame are containers in your window. You could use pack in your root and use grid in a frame, without getting any error.
So what I usally do is to imagin the root as filled area of space and I seperate it in my head to some sort of chunks where I place my frames. Like this:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
header = tk.Frame(root)
body = tk.Frame(root)
bottom_line = tk.Frame(root)
header.pack(side='top')
body.pack()
bottom_line.pack(side='bottom')
After this I fill the containers/frames with the content it belongs to like:
#header content
headline = tk.Label(header, text='At what time do you want to do each?')
headline.pack(fill='x')
#body content
first_activity = tk.Label(body,text='running:')
first_from = tk.Entry(body)
first_sep = tk.Label(body, text='to')
first_to = tk.Entry(body)
first_activity.pack(side='left')
first_from.pack(side='left')
first_sep.pack(side='left')
first_to.pack(side='left')
#bottom content
my_button = tk.Button(bottom_line, text='Enter')
my_button.pack(fill='x')
For more details [click]
PS:
If you really want to use grid and your set of envoirment, you could also use
prompt.grid(row=0, column=0,columnspan=4). But it looks a little bit different.
You can use sticky="e" on label0.grid(...):
label0.grid(row=w+1, column=0, sticky="e")

How to correct the output from an entry box

When using the feeder button, the script for F runs through entirely through to the print before the 'master' box appears, then does not react to the inputs from the 'master' box. This results in the output being 0.0 kW because the input is a long decimals followed by an L, when what I, the user inputs is 8777
I have been roaming the internet for about a day now with no luck finding anything. I am very new to TK but have been trying to learn it.
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry1 = tk.Entry(master)
entry1.grid(row=0, column=1)
button2 = tk.Button(master,
text=' Confirm',
command=entry1.get())
button2.pack()
button2.grid(row=0, column=2)
fn = entry1.pack()
print fn
feed = filtered['Feeder']==fn
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
print 'The total PV on this feeder is:', AcPv, 'kW'
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
button = tk.Button(frame,
text='Exit',
fg='red',
command=quit)
button.pack()
button.grid(row=1, column=1)
Fee = tk.Button(frame,
text='Feeder',
command=F)
Fee.pack()
Fee.grid(row=0, column=1)
root.mainloop()
Expected 27.702
Output 0.0
Given that I will not be posting the csv,
entry1/fn should be 8777
currently 'none'
UPDATE
I am now receiving an output of PY_VAR when printing fn, I understand that the code is running all the way through before taking an input. Any recommendations for how to take the input before the filters are run?
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry1 = tk.Entry(master)
entry1.grid(row=0, column=1)
button2 = tk.Button(master,
text=' Confirm',
command=entry1.get())
button2.grid(row=0, column=2)
fn = tk.IntVar()
print fn
feed = filtered['Feeder']==fn
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
print 'The total PV on this feeder is:', AcPv, 'kW'
For those interested in the final code (Which worked for me):
def F():
master = tk.Tk()
tk.Label(master, text = 'Feeder Number: ').grid(row=0)
entry = tk.Entry(master)
entry.grid(row=0, column=1)
def pint():
data = entry.get()
master.destroy()
feed = filtered['Feeder']==data
feedfn = filtered[feed]
Cap = feedfn['AC Name Plate Capacity <= 10kw']
Cap = Cap.astype(float)
AcPv = Cap.sum()
fdf = tk.Tk()
tk.Label(fdf, text = AcPv).grid(row=0)
button4 = tk.Button(fdf,
text = ' Exit',
fg='red',
command=fdf.destroy)
button4.grid(row=1)
button2 = tk.Button(master,
text=' Confirm',
command = pint)
button2.grid(row=0, column=2)
button3 = tk.Button(master,
text = ' Exit',
fg='red',
command=master.destroy)
button3.grid(row=0, column=3)
master.mainloop()
There a few mistake in your code that lead to the different output you have received.
First, why is your code executing without showing the master box :
Your tkinter need a mainloop() call if you want a persistent window.
master.mainloop()
You did that right with your root, but your master lacks that mainloop. This line is what basically keeping your GUI alive and looping over it for changes until it is destroyed one way or another. You need to add this line after creating your widgets in order to be able to interact with the window. Anything written after this line (but still indented in the definition) will be executed when your window is closed, either manually or with the command :
master.destroy()
Next, although this will yield a working window, you can still interact with your root window while the master window is up, which can lead to problems if you are expecting variable from master. I suggest you read about the Toplevel widget which is made specifically for cases like yours. (http://effbot.org/tkinterbook/toplevel.htm) Alternatively, you could also use tkinter's tkSimpleDialog.askinteger or askfloat functions which seems perfect for your application.
Finally, the entry allows you to write text but how to access the text? you can use Entry1.get() to extract the content of the entry, or as you have started to to in your update, you can assign a tkinter variable to the entry. This variable will be updated as you change write strings or numbers in the entry. To bind the variable to your entry, you must state it in the entry's creation :
fn = tk.StringVar(value = '000')
entry1 = tk.Entry(master, textvariable = fn)
*Note, this will require your fn variable to be initialized before the entry. Also, you can initialize a value for that variable upon creation
the tkinter variable is an object which is why when you print it, you get PY_VAR. (the type of object) To access the value, you need to use the get() method :
print(fn.get())

How to position several widgets side by side, on one line, with tkinter?

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

How to position widgets using tkinter (entries,labels)

I want to create a GUI with Tkinter, such that you are at a grocery store, you enter the item, price, and quantity, and each item will appear on the top part of the screen.
I have a top and bottom frame, and when I place an entry it goes right in the middle of the bottom frame. I have tried justifying the position to the left, anchoring it, sticking it and doing whatever, but it's not moving.
This is my code.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
actual = MenuBoard(root)
root.mainloop()
-Use
bottomFrame.grid_propagate(False)
to expand the frame and
storeItemEntry.grid(pady=30)
Or whatever value you want for pady. You might have to give row and column numbers to grid() if you're going to place other widgets in bottomFrame.
You saw "a strange dark grey background" as mentioned in the comment because you gave bg = "grey" to bottomFrame. The background wasn't visible initially because the frame shrank to fit the Entry. You can change the color to what you want or remove it entirely.
The following should be close to what you're looking for:
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), textvariable=textInput, bd =4)
storeItemEntry.grid(pady=30)
actual = MenuBoard(root)
root.mainloop()
UPDATE:
Based on your comments, here is a rough implementation to work with.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
mainFrame.grid_propagate(False)
mainFrame.grid_columnconfigure(0, weight=1)
heading = " Store Item".ljust(45)[:45] + "Item Price" # Pad the text with white spaces
listHeading = Label(mainFrame, text=heading, anchor="w", font=("Courier New",14,"bold"))
listHeading.grid(row=1, column=0, pady=5, stick="we")
# Use Text widget so you can keep inserting items
self.listItems = Text(mainFrame, font=("Courier New",12))
self.listItems.grid(row=2, column=0, pady=5, stick="we")
self.listItems.config(state="disabled") # Prevents edits on the Text
welcomeLabel = Label(mainFrame, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0, stick="we")
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemLabel = Label(bottomFrame, text="Food Item: ")
storeItemLabel.grid(row=0, column=0)
self.storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.storeItemEntry.grid(row=0, column=1, pady=15)
priceLabel = Label(bottomFrame, text="Price: ")
priceLabel.grid(row=2, column=0)
self.priceEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.priceEntry.grid(row=2, column=1,)
btn = Button(bottomFrame, text="Add Item", command=self.add)
btn.grid(row=3, column=1, pady=15)
def add(self):
price = self.storeItemEntry.get() # Get item name from Entry
#Get price, format name and price
groceryItem = price.ljust(50)[:50] + "$%s" %(self.priceEntry.get())
self.listItems.config(state="normal") # Enable edits on the Text
self.listItems.insert("end", "\n "+groceryItem) # Edit Text
self.listItems.config(state="disabled") # Prevents edits on the Text
actual = MenuBoard(root)
root.mainloop()
A couple of things to note:
I removed some of your frames because they seemed redundant, you can add them back if needed.
Since you're working with a class, I added the self keyword to some of the attributes so I can use/call them later in other methods without errors. I left out the attributes that I do not need to call after creation.
StringVar/textvariable is not needed since you're updating the list with a button click.
There are lots of refinements I did not do (i.e. checking to see if a valid input is given before updating the list, ability to delete from the list, etc).
I used methods and features that you may or may not be aware of (.ljust(50)[:50], %s, etc)
I hope this helps :).

How to make a background image on frame in python

I have a problem i want to put a image as the background for this little converter can someone help me? I was looking online and on stackoverflow but none of the things i found would work with the class.
__author__ = 'apcs'
from tkinter import *
class FarenheitToCelsius(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Farenheit To Celsius Conversion")
self.grid()
self.farenheitLabel = Label(self, text="Farenheit")
self.farenheitLabel.grid(row=0, column=0)
self.farVar = DoubleVar()
self.farEntry = Entry(self, textvariable=self.farVar)
self.farEntry.grid(row=0, column=1)
self.celsiusLabel = Label(self, text="Celsius")
self.celsiusLabel.grid(row=1, column=0)
self.celVar = DoubleVar()
self.celEntry = Entry(self, textvariable=self.celVar)
self.celEntry.grid(row=1, column=1)
self.button = Button(self,
text="Convert to Celsius",
command=self.convertToFarenheit)
self.button2 = Button(self,
text="Convert to Farenheit",
command=self.convertToCelsius)
self.button.grid(row=2, column=1, columnspan=1)
self.button2.grid(row=2, column=0, columnspan=1)
def convertToFarenheit(self):
fare = self.farVar.get()
cels = (fare - 32) * 5 / 9
self.celVar.set(cels)
def convertToCelsius(self):
cel = self.celVar.get()
far = cel * 9 / 5 + 32
self.farVar.set(far)
def main():
FarenheitToCelsius().mainloop()
main()
I can think of at least three ways to do this:
Create an image in a label, and use place to put it in the frame. Then create all of the other widgets and use pack or grid as you normally would. Make sure you create the frame first, then the label with the image, then the children of the frame, so that the stacking order is correct.
Use a canvas instead of a frame, and use the create_image method to add an image. Then you can pack/place/grid children as normal.
Instead of a frame, use a label as the container, and then pack/place/grid widgets into the label (yes, you can add children to a label widget).

Categories

Resources