Python GUI using Tkinter - widget positioning is not proper - python

I am creating a GUI wherein I have a TextBox, and a few Buttons.
The problem is, the layout seems to be scrambled. And when I increase the row number so that I could space out well, it doesn't make any difference. I am not sure where I have made a mistake.
Code:
from Tkinter import *
from tkFileDialog import *
gui = Tk() #create an object
gui.title("xyz")
gui.geometry("900x300")
GuiLabel1 = Label(gui,text="hi everyone!!!!!!")
GuiLabel1.grid(row=0, column=0)
GuiLabel2 = Label(gui,text="File")
GuiLabel2.grid(row=1, column=0)
bar=Entry(gui)
bar.grid(row=1, column=1)
button1= Button(gui, text="Browse")
button1.grid(row=1, column=2)
button2= Button(gui, text="Process")
button2.grid(row=2, column=2)
button3= Button(gui, text="ABC")
button3.grid(row=3, column=0)
button4= Button(gui, text="ABC")
button4.grid(row=3, column=1)
button5= Button(gui, text="ABC")
button5.grid(row=3, column=2)
button6= Button(gui, text="ABC")
button6.grid(row=3, column=3)
button7= Button(gui, text="ABC")
button7.grid(row=3, column=4)
gui.mainloop()
See the below image for the screenshot of the GUI:

The widgets are appearing pretty much exactly as you have told them to appear. The problem is, you are relying on a lot of defaults for positioning which is probably why they don't appear on the screen the way you think they should.
When you use grid, you should almost always include the sticky option to define how a widget will fill the cell it has been placed in. You often need to augment that with padding. Finally, you should generally give at least one row and one column a non-zero weight.
Also, remember that you're creating a grid. If you have a very wide item in the grid, that will cause the entire column to be wide. If you place smaller items in subsequent rows they will by default be centered in that column.

You can use the "width=" parameter to evenly space widgets see http://effbot.org/tkinterbook/button.htm and row/columnconfigure to show empty rows/columns
from Tkinter import *
gui = Tk() #create an object
gui.title("xyz")
gui.geometry("900x300")
GuiLabel1 = Label(gui,text="hi everyone!!!!!!")
GuiLabel1.grid(row=0, column=0)
GuiLabel2 = Label(gui,text="File")
GuiLabel2.grid(row=3, column=0)
bar=Entry(gui)
bar.grid(row=1, column=1)
button1= Button(gui, text="Browse", width=test_width)
button1.grid(row=1, column=2)
button2= Button(gui, text="Process", width=test_width)
button2.grid(row=2, column=2)
test_width=20
for ctr in range(4):
button= Button(gui, text="ABC"+str(ctr+1), width=test_width)
button.grid(row=3, column=ctr)
## empty column between
gui.columnconfigure(4, minsize=50)
button7= Button(gui, text="ABC")
button7.grid(row=3, column=5)
gui.mainloop()

I Think you may be looking for a mixture of
pack()
grid()
and also the element Frame which allows you to 'group' elements in it that count as one element.
I can not fix your code but I suggest you look into those and have a try.

Related

How do I fill empty space using grid system in tkinter?

I have 5 buttons with 3 of them in the first row and 2 in the second row. How do I fill the white space that is left? I tried the following:
Date_play.grid(row=3,column=1,columnspan=2,sticky="w")
File_play.grid(row=3,column=2,columnspan=2,sticky="e")
Thanks in advance.
There are multiple ways to do this. One of the easier ones is to play around with the Grid Layout.
Try this:
import tkinter as tk
root = tk.Tk()
# create a grid of 2x6
root.rowconfigure(0, weight=1)
root.rowconfigure(1, weight=1)
for i in range(6):
root.columnconfigure(i, weight=1)
# by playing around with columnspan, you can get the layout that you need
button1 = tk.Button(root, text='1')
button1.grid(row=0, column=0, columnspan=2, sticky=tk.NSEW)
button2 = tk.Button(root, text='2')
button2.grid(row=0, column=2, columnspan=2, sticky=tk.NSEW)
button3 = tk.Button(root, text='3')
button3.grid(row=0, column=4, columnspan=2, sticky=tk.NSEW)
button4 = tk.Button(root, text='4')
button4.grid(row=1, column=0, columnspan=3, sticky=tk.NSEW)
button5 = tk.Button(root, text='5')
button5.grid(row=1, column=3, columnspan=3, sticky=tk.NSEW)
root.mainloop()
You can try and add space to the text in each button.
If the text is something like:
Date Module
Just expand it like this:
Date Module
It will make the button be bigger.
Also, you can use the width attribute of each button:
date_module_button.configure(width=...)
In both of the options, you need to play with it, add more/less space, add more/less width, until you are happy with the size of the button.
try this:
Date_play.grid(row=3,column=0,columnspan=2,sticky="w")
File_play.grid(row=3,column=2,columnspan=1,sticky="e")
grid system does not allow to fill half the grid.
best to do is make a new frame without a highlighted boarder, place them just below the row 2 in that frame add your two button.
bottonframe = Frame(root)
bottoframe.grid(row = 3, columnspan=3, width = <as per your window>)
Date_play = Button(buttonframe,<your button config>)
File_play = Button(buttonframe,<your button config>)
Date_play.grid(row=1,column=1,sticky="w")
File_play.grid(row=1,column=2,sticky="e")
and then little bit adjustment.

How can i attach my scroll bar to my text box on tkinter?

Im trying to use a vertical scrollbar for my text box but am coming across some problems:
I cant get the scroll bar to be directly touching the right side of the text box (so they are connected)
It seems the scroll bar wont affect my text box
I looked through some solutions but none seemed to work.
Heres my code:
from tkinter import *
writtenQ = Tk()
writtenQ.title("Written Response Question")
writtenQ.resizable(0,0)
header = LabelFrame(writtenQ, bg="white")
content = LabelFrame(writtenQ, bg="white")
header.columnconfigure(0, weight=1) # Forces column to expand to fill all available space
homeButton=Button(content,width=50,height=50)
try:
homeIcon=PhotoImage(file="yes.png")
homeButton.config(image=homeIcon)
homeButton.image = homeIcon
except TclError:
print("Home")
homeButton.grid(row=1, sticky="w", padx=15, pady=2)
#the image of the question will be put here
titleHeader = Label(content, text="Question Image here",pady=15, padx=20, bg="white", font=("Ariel",20, "bold"), anchor="w", relief="solid", borderwidth=1)
titleHeader.grid(row=2, column=0, columnspan=3, padx=15, pady=5, ipadx=370, ipady=150)
#this will allow the user to input their written response
answerInput = Text(content, width = 60, borderwidth=5, font=("HelvLight", 18))
answerInput.grid(row=3, column=0, ipady = 10, sticky="w", padx=(20,0), pady=20)
answerScrollBar= Scrollbar(content, command=answerInput.yview, orient="vertical")
answerScrollBar.grid(row=3, column=1, sticky="w")
submitButton = Button(content, borderwidth=1, font=("Ariel", 22), text="Submit", bg="#12a8e3", fg="black", activebackground="#12a8e3", relief="solid")
submitButton.grid(row=3, column=2, ipady=50, ipadx=70, sticky="nw", pady=20)
header.grid(row=0, sticky='NSEW')
content.grid(row=1, sticky='NSEW')
Configuring a scrollbar requires a two-way connection: the scrollbar needs to call the yview or xview method of the widget, and the widget needs to call the set method of the scrollbar.
Usually, this is done in three steps like in the following example:
answerInput = Text(...)
answerScrollBar= Scrollbar(..., command=answerInput.yview)
answerInput.configure(yscrollcommand=answerScrollBar.set)
You are forgetting the final step.
Unrelated to an actual functioning scrollbar, you're going to want to be able to see the scrollbar. You need to use sticky="ns" for the scrollbar so that it stretches in the Y direction. Otherwise it will only be a couple dozen pixels tall.
answerScrollBar.grid(row=3, column=1, sticky="ns")
Have you tried the solution here?
Let's say that the text widget is called text. Your code could be (excluding the setup of the window):
import tkinter
import tkinter.ttk as ttk
scrollb = ttk.Scrollbar(self, command=text.yview)
scrollb.grid(row=0, column=1, sticky='nsew')
text['yscrollcommand'] = scrollb.set
I have picked out what I think will be ueful for you from Honest Abe's answer. Hope it helped. Remember to set up your window before using the code...

How do I align something to the bottom left in Tkinter using either .grid() or .pack()?

I am currently trying to make a game in Tkinter which uses multiple different windows.
However, as I am trying to create the layout of a secondary window, I can't seem to get my Return to Menu button underneath the list box, and aligned to the left. I have tried it using .pack() and .grid() methods, but they don't make sense to me.
I've tried using .pack():
header = Frame(wn).pack()
title = Label(header, text='Single-Player',font=('Arial bold',20),bg=bgcolor).pack(anchor='center')
footer = Frame(wn).pack(side=BOTTOM)
return_to_menu = Button(footer, text='Return to Main Menu',font=('Arial',16),bg=bgcolor,command=lambda: menu()).pack(side=BOTTOM,padx=20,pady=250)
# body frame (left side)
bodyL = Frame(wn).pack(side=LEFT)
#output box
output = Listbox(bodyL, width=50, font=("Arial", 20)).pack(side=LEFT,padx=15)`
And I've tried using .grid():
header = Frame(wn).grid(sticky=N)
title = Label(header, text='Single-Player',font=('Arial bold',20),bg=bgcolor).grid(sticky=N+E+W,row=0,column=0)
footer = Frame(wn).grid(sticky=S)
return_to_menu = Button(footer, text='Return to Main Menu',font=('Arial',16),bg=bgcolor,command=lambda: menu()).grid(sticky=S,padx=20,row=0,column=0)
# body frame (left side)
bodyL = Frame(wn).grid(sticky=W)
#output box
output = Listbox(bodyL, width=50, font=("Arial", 20)).grid(sticky=W,padx=15, )`
However using .grid() doesn't align my title to the center of the screen anymore.
Is there a way to center it more efficiently - I didn't like using padx=450 to get it centered.
What happens with the button and the list box, is the button appears to the left of the list box, instead of on the bottom. I have attempted several other methods, such as incrementing row numbers, but my script doesn't appear to do what I anticipated.
Here is an example of how you can set up the weight of specific columns and row to get widgets to stick to a specific location on the screen.
With the use of grid() we need to use columnconfigure() and rowconfigure() to make this work.
These 2 methods are used to define at what ratio the column or row will expand in relation to the columns or rows around it as the container grows or shrinks.
See below example and let me know if you have any questions:
import tkinter as tk
root = tk.Tk()
for i in range(3):
root.columnconfigure(i, weight=1)
root.rowconfigure(1, weight=1)
tk.Label(root, text='Top left').grid(row=0, column=0, sticky='w')
tk.Label(root, text='Top center').grid(row=0, column=1)
tk.Label(root, text='Top right').grid(row=0, column=2, sticky='e')
tk.Label(root, text='center').grid(row=1, column=1)
tk.Label(root, text='Bottom left').grid(row=2, column=0, sticky='w')
tk.Label(root, text='Bottom center').grid(row=2, column=1)
tk.Label(root, text='Bottom right').grid(row=2, column=2, sticky='e')
root.mainloop()
Example:
Here is another example but this time I have a title label outside of a frame so that we can make it easier to manage the title being centered and then working with all the other content of the frame is separate from the title label.
import tkinter as tk
root = tk.Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(1, weight=1)
frame = tk.Frame(root)
frame.grid(row=1, column=0, sticky='nsew')
for i in range(3):
frame.columnconfigure(i, weight=1)
frame.rowconfigure(1, weight=1)
tk.Label(root, text='Title centered').grid(row=0, column=0)
tk.Label(frame, text='Top left').grid(row=0, column=0, sticky='w')
tk.Label(frame, text='Top center').grid(row=0, column=1)
tk.Label(frame, text='Top right').grid(row=0, column=2, sticky='e')
tk.Label(frame, text='Center').grid(row=1, column=1)
tk.Label(frame, text='Bottom left').grid(row=2, column=0, sticky='w')
tk.Label(frame, text='Bottom center').grid(row=2, column=1)
tk.Label(frame, text='Bottom right').grid(row=2, column=2, sticky='e')
tk.Label(root, text='Footer centered').grid(row=2, column=0)
root.mainloop()
Example:
To address your problem in the comments you cannot use grid() or any other geometry manager for that matter on the same line you create your container. This will always cause the variable for that frame to return None as the geometry managers return None when called.
See this image as to what happens when you use grid() on the same line you create your container.
Now if you delete the grid() part on the row that your container is created and then write it on the next line as the commented out section of the above images shows it will work as expected. See below image of proper use of grid() for containers.
To address your 2nd question in the comments you can add this line to provide a button at the bottom left.
tk.Button(root, text='Bottom left button').grid(row=3, column=0, sticky='w')
Example:

How to justify text in label in Tkinter

In Tkinter in Python:
I have a table with a different label. How can I justify the text that is in the label? Because It is a table and the texts in different labels come together!
from tkinter import *
root=Tk()
a=Label(root,text='Hello World!')
a.pack()
a.place(x=200,y=200)
b=Label(root,text='Bye World')
b.pack()
b.place(x=200,y=100)
I want something for justifying in center some text in label but it is not something that I need plz check this: link
By default, the text in a label is centered in the label. You can control this with the anchor attribute, and possibly with the justify attribute. justify only affects the text when there is more than one line of text in the widget.
For example, to get the text inside a label to be right-aligned you can use anchor="e":
a=Label(root,text='Hello World!', anchor="e")
Note, however, this will appear to have no effect if the label is exactly big enough to hold the text. In your specific example, you would need to give each label the same width:
a=Label(..., width=12)
b=Label(..., width=12)
To add on to what Bryan said, LEFT is the constant you are looking for to correctly format your wrapped text. You can also justify to the RIGHT or CENTER (the default).
a=Label(root,text='Hello World!', anchor="e", justify=LEFT)
instead of using .pack() i would use .grid()
The Tkinter Grid Geometry Manager
grid will allow better management of your components
find bellow an example of usage and management:
Label(root, text="First").grid(row=0, sticky=W)
Label(root, text="Second").grid(row=1, sticky=W)
entry1 = Entry(root)
entry2 = Entry(root)
entry1.grid(row=0, column=1)
entry2.grid(row=1, column=1)
checkbutton.grid(columnspan=2, sticky=W)
image.grid(row=0, column=2, columnspan=2, rowspan=2,
sticky=W+E+N+S, padx=5, pady=5)
button1.grid(row=2, column=2)
button2.grid(row=2, column=3)
you would endup using the grid option padx="x" to "justify" your labels

Adding Python Text Area To Existing Program

I have a little python program. I'm using Tkinter for a GUI. I have a bunch of grid style text boxes, but i want to add a small text area. All the examples Ive tried work, but open in a new window.
I want the last grid labeled "description" to be a small text area instead, As it would be used for a few sentences rather than a few words. Also im going to need to "get()" this input to use as a variable.
Here is my script.( I left out a few parts that might bring up errors )
from Tkinter import *
master = Tk()
Label(master, text="Stock #").grid(row=0, sticky=W)
Label(master, text="Type").grid(sticky=W, row=1)
Label(master, text="Make").grid(sticky=W, row=2)
Label(master, text="Model").grid(sticky=W, row=3)
Label(master, text="GVW").grid(sticky=W, row=0, column=2)
Label(master, text="Description").grid(sticky=W, row=1, column=2)
e1 = Entry(master)
e2 = Entry(master)
e3 = Entry(master)
e4 = Entry(master)
e24 = Entry(master)
e25 = Entry(master)
e1.grid(row=0, column=1, pady=5, padx=(0,30))
e2.grid(row=1, column=1, pady=5, padx=(0,30))
e3.grid(row=2, column=1, pady=5, padx=(0,30))
e4.grid(row=3, column=1, pady=5, padx=(0,30))
e24.grid(row=0, column=3, pady=5, padx=(0,10))
e24.insert(0, "N/A")
e25.grid(row=1, column=3, pady=5, padx=(0,10))
e25.insert(0, "N/A")
mainloop( )
I want the last grid labeled "description" to be a small text area instead, As it would be used for a few sentences rather than a few words.
As the Entry docs tell you:
To enter multiple lines of text, use the Text widget.
So:
text = Text(master)
text.grid(row=whatever, etc.)
Also im going to need to "get()" this input to use as a variable.
I'm not sure what you mean here. If you mean you wanted to attach a StringVar, you can't do that with Text, sadly, only with Entry. But if you want to be able to fetch the contents in some way, you don't care which way, then that's easy; the Text docs will show you how a variety of different ways, but I think text.get(1.0, END) is the one you'll probably want.

Categories