When I run the code below I do not get an error but the bottom frame doesn't appear in the window please can you tell me why and how I can make it appear (using the pack method NOT GRID please). I am using Python 3.5.0
import tkinter
from tkinter import *
root = tkinter.Tk()
root.geometry("1920x1080")
TopFrame = Frame(root, width=1920, height=200, bg= "green")
TopFrame.pack(side=TOP)
MiddleRightFrame = Frame(root, width=1120, height=730, bg="orange")
MiddleRightFrame.pack(side=RIGHT)
MiddleLeftFrame = Frame(root, width=800, height=730, bg="black")
MiddleLeftFrame.pack(side=LEFT)
BottomFrame = Frame(root, width=1920, height=150, bg="blue")
BottomFrame.pack(side=BOTTOM)
Your MiddleLeftFrame is 800 pixels wide. Your MiddleRightFrame is 1120 pixels. 1120 + 800 = 1920. You're forcing the window to be only 1920 pixels wide, so there's no room for the blue frame.
Remove this line and your frame will appear: root.geometry("1920x1080")
If your intent is for it to appear at the bottom of the window, spanning the entire width of the window, then call pack on it before you call pack on the left and right sides.
Also, I strongly recommend grouping your pack statements together. It makes the code easier to manage in my experience (and I have a lot of experience!).
import tkinter
from tkinter import *
root = tkinter.Tk()
root.geometry("1920x1080")
TopFrame = Frame(root, width=1920, height=200, bg= "green")
MiddleRightFrame = Frame(root, width=1120, height=730, bg="orange")
MiddleLeftFrame = Frame(root, width=800, height=730, bg="black")
BottomFrame = Frame(root, width=1920, height=150, bg="blue")
TopFrame.pack(side=TOP)
BottomFrame.pack(side=BOTTOM)
MiddleRightFrame.pack(side=RIGHT)
MiddleLeftFrame.pack(side=LEFT)
root.mainloop()
The reason this works is due to the packer algorithm. When you place something on the left or right, it will allocate all of the remaining vertical space on that side. Thus, after you pack something on the left and right and then later pack something on the bottom, the "bottom" is the bottom of the space between the left and right, not the bottom of the window as a whole.
Here is the canonical description of how pack works:
http://tcl.tk/man/tcl8.5/TkCmd/pack.htm#M26
I think the issue is that you are using pack sides so that in the middle there is a line of nothing. One way to get around this is to create a MiddleFrame where pack sides are used and then just pack the other frames.
import tkinter
from tkinter import *
root = tkinter.Tk()
root.geometry("1920x1080")
TopFrame = Frame(root, width=1920, height=200, bg= "green")
TopFrame.pack()
#the middle frame
MiddleFrame = Frame(root)
#pack the two middle frames into the frame created above
#the parent of the two middle frames change to become MiddleFrame instead of root
MiddleRightFrame = Frame(MiddleFrame, width=1120, height=730, bg="orange")
MiddleRightFrame.pack(side=RIGHT)
MiddleLeftFrame = Frame(MiddleFrame, width=800, height=730, bg="black")
MiddleLeftFrame.pack(side=RIGHT)
#pack the middle frame with both frames inside it
MiddleFrame.pack()
BottomFrame = Frame(root, width=1920, height=150, bg="blue")
BottomFrame.pack()
Add:
tkinter.mainloop()
so that the GUI starts waiting for events as opposed to skipping to close itself.
Additionally, pack uses a filling algorithm which calculates dynamically to fill the empty space. You shouldn't really be doing it like this but a simple call swap would suffice in this specific case. Call:
BottomFrame.pack(side=BOTTOM)
exactly after TopFrame's pack:
TopFrame.pack(side=TOP)
BottomFrame.pack(side=BOTTOM)
MiddleRightFrame.pack(side=RIGHT)
MiddleLeftFrame.pack(side=LEFT)
Related
I'm trying to figure out how to choose which part of the panel changes sizes when changing the size of the window. The way it goes right now is that every time I change the size of the window, it's the panel on the right or the one on the bottom the ones that change while the one on the left and the one on the top remain the same size. I want it to be the other way around. I want it to be so that the one that changes size is the one on the left, not the one on the right. I've tried changing the different parameters for pack but it affects the whole panel, not just one side.
This is the code I'm using as a reference.
from tkinter import *
root = Tk()
root.title("Hello World!")
root.geometry("400x400")
panel_1 = PanedWindow(bd=4, relief="raised", bg="red")
panel_1.pack(fill=BOTH, expand=1)
left_label = Label(panel_1, text="Left Panel")
panel_1.add(left_label)
panel_2 = PanedWindow(panel_1, orient=VERTICAL, bd=4, relief="raised", bg="blue")
panel_1.add(panel_2)
top = Label(panel_2, text="Top Panel")
panel_2.add(top)
bottom = Label(panel_2, text="Bottm Panel")
panel_2.add(bottom)
root.mainloop()
Here is the modified code following #jasonharper advice.
from tkinter import *
root = Tk()
root.title("Hello World!")
root.geometry("400x400")
panel_1 = PanedWindow(bd=4, relief="raised", bg="red")
panel_1.pack(fill=BOTH, expand=1)
left_label = Label(panel_1, text="Left Panel")
panel_1.add(left_label, stretch="always")
panel_2 = PanedWindow(panel_1, orient=VERTICAL, bd=4, relief="raised", bg="blue")
panel_1.add(panel_2, stretch="never")
top = Label(panel_2, text="Top Panel")
panel_2.add(top)
bottom = Label(panel_2, text="Bottm Panel")
panel_2.add(bottom)
root.mainloop()
I want to fit this frame with scrollbar(refer the provided image) in the black space present in the provided image. How do I do that. The frame should totally cover the black space.
The code for program.The image
from tkinter import *
from tkinter import ttk
C = Tk()
C.maxsize(1200, 750)
C.geometry("1200x750")
C.title("Mainscreen")
style = ttk.Style()
style.theme_use('clam')
BG = PhotoImage(file="Mainscreen bg.png")
ML = PhotoImage(file="Music_label.png")
BG_label = Label(C, image=BG, border=0)
BG_label.place(x=0, y=0)
style.configure("Vertical.TScrollbar", gripcount=0,
background="Cyan", darkcolor="gray6", lightcolor="LightGreen",
troughcolor="Turquoise4", bordercolor="gray6", arrowcolor="gray6",arrowsize=15)
wrapper1= LabelFrame(C, width="1600", height="100", background="gray6",bd=0)
mycanvas = Canvas(wrapper1,background="gray6",borderwidth=0, highlightthickness=0, width=700, height=600)
mycanvas.pack(side=LEFT, expand="false", padx=0)
yscrollbar = ttk.Scrollbar(wrapper1, orient="vertical",command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill="y")
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>',lambda e: mycanvas.configure(scrollregion=mycanvas.bbox("all")))
myframe = Frame(mycanvas)
mycanvas.create_window((0,0), window=myframe, anchor="n")
wrapper1.pack(side=RIGHT,expand="false", padx=0, pady=200)
for i in range(50):
Button(myframe, image=ML,bg="gray6",bd=0).pack()
mainloop()
EDIT:
Music_Label
Mainscreen bg
So after trying to understand the underlying problem for a while I have reached the conclusion, that the problem is with the fact that the button are being drawn in the myframe and the myframe is outside the mycanvas which contains the scrollbar. So by changing the master widget for the button from myframe to mycanvas, the problem gets fixed now the scrollbar is adjacent to the buttons. BUT, Also now the button r shifted the side since while packing the wrapper1, you did side = RIGHT, so I would also suggest that you use place here instead of pack, since pack depends on the space available and is not reliable if you are using a Background for your GUI and want the buttons within a portion of it.
I have changed the following lines -:
Button(mycanvas, image=ML,bg="gray6",bd=0).pack() # Changed to mycanvas from myframe
and
wrapper1.place(x = {YOUR X, WHERE THE BOX STARTS}, y = {YOUR Y, WHERE THE BOX STARTS}) # Use place instead..
You can use pack also, and change the padx and pady arguments but it will be tricky to get it to work always as expected.
The fixed code is this -:
from tkinter import *
from tkinter import ttk
C = Tk()
C.maxsize(1200, 750)
C.geometry("1200x750")
C.title("Mainscreen")
style = ttk.Style()
style.theme_use('clam')
BG = PhotoImage(file="Mainscreen bg.png")
ML = PhotoImage(file="Music_label.png")
BG_label = Label(C, image=BG, border=0)
BG_label.place(x=0, y=0)
style.configure("Vertical.TScrollbar", gripcount=0,
background="Cyan", darkcolor="gray6", lightcolor="LightGreen",
troughcolor="Turquoise4", bordercolor="gray6", arrowcolor="gray6",arrowsize=15)
wrapper1= LabelFrame(C, width="1600", height="100", background="gray6",bd=0)
mycanvas = Canvas(wrapper1,background="gray6",borderwidth=0, highlightthickness=0, width=700, height=600)
mycanvas.pack(side=LEFT, expand=False, padx=0)
yscrollbar = ttk.Scrollbar(wrapper1, orient="vertical",command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill="y", expand = False)
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>',lambda e: mycanvas.configure(scrollregion=mycanvas.bbox("all")))
myframe = Frame(mycanvas)
mycanvas.create_window((0,0), window=myframe, anchor="n")
wrapper1.pack(expand=True, padx=0, pady=200) # Use place instead
for i in range(50):
Button(mycanvas, image=ML,bg="gray6",bd=0).pack() # Change this to mycanvas from myframe
mainloop()
This is my first time using tkinter and I already did some research on pack and grid. How do I fix this code so that the pack and grid components don't intertwine?
I want to use grid for my checkbox so that 16 checkboxes show up in a column next to the words corresponding to them. Can I do this with pack?
# tkinter will help us with the GUI
import tkinter as tk
from tkinter import filedialog, Text
import os
def data():
categoriesArray = ["16 words here"]
for i in range(16):
checkbox = tk.Checkbutton(buttonFrame, bg="white")
checkbox.grid(row=i, column=0, sticky="w")
tk.Label(canvasFrame, text=categoriesArray[i]).grid(row=i, column=1, sticky="ew")
# Define the scrolling function for the scrollbar
def scrollFunction(event):
canvas.configure(scrollregion=canvas.bbox("all"), width=200, height=500)
# The root holds the whole app structure. Always attach to root.
root = tk.Tk()
# These two lines literally make the rectangular structure of the app.
canvas = tk.Canvas(root, height = 500, width= 1300, bg="#00008B")
canvas.pack()
# These two lines make the white screen you see on the left of the buttons.
frame = tk.Frame(root, bg="white")
frame.place(relwidth=0.8, relheight=0.8, relx=0.03, rely=0.1)
# This is the frame for the buttons on the right
buttonFrame = tk.Frame(root, bg="white")
buttonFrame.place(relwidth=0.13, relheight=0.8, relx=0.85, rely=0.1)
# You need a canvas to define a scrollbar within the app.
# Resource: https://stackoverflow.com/questions/16188420/tkinter-scrollbar-for-frame
canvas=tk.Canvas(buttonFrame)
canvasFrame=tk.Frame(canvas)
scrollbar=tk.Scrollbar(buttonFrame, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
canvas.pack(side="left")
canvas.create_window((36,0), window=canvasFrame, anchor='nw')
canvasFrame.bind("<Configure>", scrollFunction)
# Call the data for the categories to show on the right
data()
# This runs the mainframe to work
root.mainloop()
Please let me know anything I can do to make my question better.
Places I've looked but gotten confused: fix this code 'cannot use geometry manager grid inside . which already has slaves managed by pack'
I fixed it. checkbox = tk.Checkbutton(buttonFrame, bg="white") should have canvasFrame instead of buttonFrame.
I am newbie in programming, don't hate me pls :)
Why scroll is not working on my canvas widget?
I added loop with 30 rows and I cannot scroll down.
Its look like it because of create_text() method or maybe not.
I've written code for example below.
from tkinter import *
root = Tk()
root.geometry('200x150')
frame = Frame(root)
yscrollbar = Scrollbar(frame, orient=VERTICAL)
yscrollbar.pack(fill=Y, side=RIGHT)
canvas = Canvas(frame,
yscrollcommand=yscrollbar.set,
bg='white')
canvas.pack(fill=BOTH)
yscrollbar.config(command=canvas.yview)
n=12
for i in range(1,31):
canvas.create_text(10,n,text=i)
n+=12
frame.pack()
root.mainloop()
Scrolling is not responsive because you need to tell the canvas to limit the scrolling to a given area.
You can use the bbox method to get a bounding box for a given object, or a group of objects.
canvas.bbox(ALL) returns the bounding box for all objects on the canvas.
Link: http://effbot.org/zone/tkinter-scrollbar-patterns.htm you can check other methods to do this in this link
Here is the working code:
from tkinter import *
root = Tk()
root.geometry('200x150')
frame = Frame(root)
yscrollbar = Scrollbar(frame, orient=VERTICAL)
yscrollbar.pack(fill=Y, side=RIGHT)
canvas = Canvas(frame,
yscrollcommand=yscrollbar.set,
bg='white')
canvas.pack(fill=BOTH)
yscrollbar.config(command=canvas.yview)
n=12
for i in range(1,31):
canvas.create_text(10,n,text=i)
n+=12
frame.pack()
# Add this line to tell the canvas the area over to scroll
canvas.config(scrollregion=canvas.bbox(ALL))
root.mainloop()
When I put in my code for this name picker, the gui opens and the two buttons are on top of each other. I understand why this is happening but I do not know how to move it.
This is what it looks like
This is what I want it to look like
Code:
from tkinter import *
import tkinter
import random
names =['Sledge','Thatcher','Ash','Thermite','Twitch','Montagne','Glaz','Fuze','Blitz','IQ','Buck','Blackbeard','Capitão','Hibana']
name = ["Smoke","Mute","Castle","Pulse","Doc","Rook","Kapkan","Tachanka","Jäger","Bandit","Frost","Valkyrie","Caveira","Echo"]
def pickName():
nameLabel.configure(text=random.choice(names))
def pickName1():
nameLabel.configure(text=random.choice(name))
root = tkinter.Tk()
root.title("Operator Picker")
root.geometry("400x100")
nameLabel = tkinter.Label(root, text="", font=('Helvetica', 32))
nameLabel.pack()
Grid()
pickButton1 = tkinter.Button(text="Pick Attack", command=pickName)
pickButton1.pack()
pickButton1.place(bordermode=OUTSIDE,height=100, width= 100)
pickButton2 = tkinter.Button(text="Pick Defend", command=pickName1)
pickButton2.pack()
pickButton2.place(bordermode=OUTSIDE,height=100, width= 100)
root.mainloop()
You don't need to pack and place your buttons, you can just pack them. If you want them on opposite sides, try this
pickButton1 = tkinter.Button(root, text="Pick Attack", command=pickName, height=100, width=100)
pickButton1.pack(side=tkinter.LEFT)
pickButton2 = tkinter.Button(root, text="Pick Defend", command=pickName1, height=100, width=100)
pickButton2.pack(side=tkinter.RIGHT)
Edit:
When you define the width and height of an object containing text, it is measured in lines and characters instead of pixels, if you want those exact sizes, you need to add frames
f1 = tkinter.Frame(root, height=100, width=100) #defines frame size in pixels
f1.pack(side=tkinter.LEFT) #packs on the left
f1.pack_propagate(0) #tells frame not to let children control size
pickButton1 = tkinter.Button(f1, command=pickName, text="Pick Attack")
pickButton1.pack(fill=tkinter.BOTH, expand=1) #takes up all available space
f2 = tkinter.Frame(root, height=100, width=100)
f2.pack(side=tkinter.RIGHT)
f2.pack_propagate(0)
pickButton2 = tkinter.Button(f2, command=pickName1, text="Pick Defend")
pickButton2.pack(fill=tkinter.BOTH, expand=1)