Maybe this is just how Tkinter works but Im unsure. Currently I have the Main window with three frames laid out next to each other. Frame ContainerFrame is a master, then characterFrame and planetFrame are placed inside the ContainerFrame. The issue is or what I would like to happen is that the frames would fill up a set area of the window regardless of whether or not their is data/ widgets in them.
Here is what I envision it to look like https://imgur.com/OjdKFh4
from tkinter import *
from tkinter import ttk
MainWindow = Tk()
def mainWindow():
MainWindow.option_add('*tearOff', False)
MainWindow.title("Interface")
MainWindow.geometry('800x600')
menubar = Menu(MainWindow)
MainWindow.config(menu = menubar)
File = Menu(menubar)
About = Menu(menubar)
menubar.add_cascade(menu = File, label = "File")
menubar.add_cascade(menu = About, label = "About")
def frameContainer():
containerFrame = Frame(MainWindow)
containerFrame.pack(anchor = "nw", side = "left", fill = "both", expand = False)
scroller = Scrollbar(orient = "vertical")
characterFrame = Frame(containerFrame, borderwidth="2", relief="sunken")
characterFrame.pack(anchor = "nw", side = "left", expand = True)
planetFrame = Frame(containerFrame ,borderwidth="2", relief="sunken")
planetFrame.pack(anchor = "nw", side = "right", expand = True)
scroller = Scrollbar(orient = "vertical")
scroller.pack(anchor = "e", side = "right", fill = "y", expand = False)
characterLable = Button(characterFrame, text ="Characters")
characterLable.pack()
Label(characterFrame, text ="Test1").pack()
Label(characterFrame, text ="Test2").pack()
Label(planetFrame, text ="Test1").pack()
Label(planetFrame, text ="Test2").pack()
mainWindow()
frameContainer()
MainWindow.mainloop()
Normally you would use a frame to organize a widget with a scrollbar, but a frame is not scrollable. If you want to scroll an area containing other widgets the usual thing to do is to use a canvas.
Study this guide: Tkinter Scrollbar Patterns
Pack can be difficult to use and the only way I have found to overcome this is to keep trying. It's usually easier to see what you are doing if you let the different frames have different bg colors. Also I've taken the liberty to change some of your variable names as they do not give a hint as to what they are or are too similar to other names, eg. mainWindow and MainWindow.
I have added some padding to some widgets to make it look better.
from tkinter import *
root = Tk()
def create_main_window():
root.option_add('*tearOff', False)
root.title("Interface")
root.geometry('400x300+800+50')
menubar = Menu(root)
root.config(menu = menubar)
File = Menu(menubar)
About = Menu(menubar)
menubar.add_cascade(menu = File, label = "File")
menubar.add_cascade(menu = About, label = "About")
def create_container_frame():
container = Frame(root, bg='tan')
container.pack(fill="both", expand=True)
scroller = Scrollbar(container, orient="vertical")
scroller.pack(side="right", fill="y")
characterFrame = Frame(container, bd=2, relief="sunken", bg='thistle')
characterFrame.pack(side="left", fill='y', padx=(10,0), pady=10)
character_button = Button(characterFrame, text ="Characters")
character_button.pack(padx=10, pady=(10,0))
Label(characterFrame, text ="Test1").pack()
Label(characterFrame, text ="Test2").pack()
planetFrame = Frame(container ,bd=2, relief="sunken", bg='khaki')
planetFrame.pack(side="left", fill='both', expand=True, padx=10, pady=10)
Label(planetFrame, text="Test1").pack(pady=(10,0))
Label(planetFrame, text="Test2").pack()
create_main_window()
create_container_frame()
root.mainloop()
Is this the layout you are aiming for?
Related
I am working on a GUI and have added some labelframes which barely fits the window. I want to add a menubar so after adding it, the last labelframe does not fit the window. Hence I want to make it scrollable. I tried many solutions on internet but still not able to scroll.
Here is the GUI pic:
Here is the code. Not sending all label frames code since one will give the idea.
self.window = Tk()
self.color = 'dark orange'
self.window.geometry('640x720')
self.window.resizable(False, False)
self.window.configure(background=self.color)
self.window.title('Classify')
#self.window.iconbitmap('py.ico')
self.frame = Frame(self.window)
self.frame.pack(expand=True, fill=BOTH)
self.canvas = Canvas(self.frame,background='dark orange')
self.v_scroll = Scrollbar(self.frame, orient=VERTICAL, command=self.canvas.yview,background='black',activebackground='black')
self.v_scroll.pack(side=RIGHT,fill=Y)
self.canvas['yscrollcommand'] = self.v_scroll.set
self.canvas.pack(expand=True, fill=BOTH)
self.frame2 = Frame(self.canvas,bg='dark orange')
self.canvas.create_window((0, 0), window=self.frame2, anchor=N + W)
self.menubar = Menu(self.frame2)
# Adding File Menu and commands
self.file = Menu(self.menubar, tearoff = 0)
self.menubar.add_cascade(label ='File', menu = self.file)
self.file.add_command(label ='New File', command = None)
self.window.config(menu = self.menubar)
self.frame = LabelFrame(self.canvas, text='File Selection', bg=self.color)
self.frame.place(width=580, height=80, bordermode=OUTSIDE, x=20,y=10)
More labelframes are there having same procedure with different y coordinate only are there but has same procedure so skipping to last lines.
self.window.update()
self.canvas.configure(scrollregion=self.canvas.bbox(ALL))
self.window.mainloop()
What changes should be done?
I'm programming something in python and I need to create a scrollbar that updates when new widgets are added to the window. I don't know how to do this and I haven't found the answer in any place. Is there a command for this? This is my code right now.
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
my_canvas = tk.Canvas(root)
my_canvas.pack(side = "left", fill = "both", expand = 1)
my_scrollbar = tk.Scrollbar(root, orient = "vertical", command = my_canvas.yview)
my_scrollbar.pack(side = "right", fill = "y")
my_canvas.configure(yscrollcommand = my_scrollbar.set)
my_canvas.bind("<Configure>", lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
my_frame = tk.LabelFrame(my_canvas, width = my_canvas.winfo_width())
my_frame.grid_propagate(0)
my_frame.pack()
for i in range(10):
my_label = tk.Label(my_frame, text = "Label")
my_label.pack()
my_canvas.create_window((0, 0), width = 600, anchor = "nw", window = my_frame)
def create_label(scroll, canv, fram):
my_label = tk.Label(fram, text="Label")
my_label.pack()
my_button = tk.Button(my_frame, text = "Button", command = lambda: create_label(my_scrollbar, my_canvas, my_frame))
my_button.pack()
root.mainloop()
Bind to the <Configure> event of the inner frame. That event fires whenever the frame changes size.
def adjust_scrollregion(event):
my_canvas.configure(scrollregion=my_canvas.bbox("all"))
my_frame.bind("<Configure>", adjust_scrollregion)
Unrelated to the question that was asked... calling my_frame.grid_propagate(0) is pointless since you use pack inside of my_frame.
I create a window in Tk() and add a background image. When I create a frame, it is covering part of the image. I already looked for some similar questions about get the frame transparent, but that is not that I want. I would like the frame to just show the buttons inside without affecting the background image.
Here is a modified code, to show you what is the problem:
from tkinter import*
from tkinter import ttk
from PIL import Image, ImageTk
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master = None)
self.master = master
self.init_window()
self.menu_option()
self.image_font()
def init_window(self):
self.master.title("ATO Home Screem")
self.master.geometry("600x400")
self.master.configure(background = "#42f4f4")
self.pack(fill = BOTH, expand = 1)
def menu_option(self):
menu = Menu(self.master)
self.master.config(menu = menu)
filemenu = Menu(menu)
menu.add_cascade(label = 'File', menu = filemenu)
filemenu.add_command(label = 'New')
filemenu.add_separator()
filemenu.add_command(label = 'Open')
filemenu.add_command(label = 'Save As')
filemenu.add_command(label = 'Save')
filemenu.add_separator()
filemenu.add_command(label = 'Exit')
def image_font(self):
image = Image.open(r"C:\Users\User\Desktop\ATO.png")
image = image.resize((600,400),Image.ANTIALIAS)
photoImg = ImageTk.PhotoImage(image)
panel = Label(self.master,image = photoImg)
panel.image = photoImg
panel.place(x = 0, y = 0, relwidth = 1, relheight = 1)
panel.configure(image = photoImg)
master = Tk()
Window(master)
frame = Frame(master)
frame.pack(fill = BOTH, expand = 1)
Button(frame, text = "Test") .place(x = 50, y = 50)
master.mainloop()
I would like to know if you have any idea of how to solve it, or if you recommend me to use another kind of GUI tool.
I am trying to make a GUI using python tkinter.
I want to print the entry text from textbox to console after the analyzebutton is pressed.
here is my code
root = Tk()
root.title('Title')
MiddleFrame = Frame(root)
BottomFrame = Frame(root)
TopFrame.pack(side = TOP)
MiddleFrame.pack()
BottomFrame.pack(side = BOTTOM)
TextArea = Text()
ScrollBar = Scrollbar(root)
ScrollBar.config(command = TextArea.yview)
TextArea.config(height = 25, width = 70,
background = "white", yscrollcommand = ScrollBar.set)
TextArea.grid(padx = 18, pady = 18)
ScrollBar.pack(side = RIGHT, fill = Y)
padx = 10
pady = 10
TextArea.pack(padx = padx, pady = pady)
AnalyzeButton = Button(BottomFrame, text = "Analyze", fg = "white", bg = "blue", command = callback)
AnalyzeButton.pack(fill = X, padx = padx, pady = pady)
def callback():
text_input = Text.get()
print(text_input)
root.mainloop()
thanks in advance
Use get method of Text. Use the widget not the class-Text. Here is what you need to do:-
text_input = TextArea.get("1.0","end-1c")
You have several problems in your code. I will break it down so you understand what is going on here.
Fist I noticed you have tried to pack TopFrame but you have not actually defined TopFrame yet. So I added TopFrame = Frame(root) to your code.
Next we have a common mistake people encounter when trying to use grid() and pack() on the same window/frame. This is not allowed by the geometry manager. So you will need to decide on either grid() or pack() for all your needs in each window/frame. For now I changed TextArea.grid() to TextArea.pack() to get your code to work.
Next your button command was referencing a function that was after the command. This does not work outside of a class so you will need to move your callback() function above your AnalyzeButton.
Next we need to fix the indention on your callback() function. You must remember indention is very important in python and you should take care to keep your indention clean and consistent.
The last thing we needed to fix to get everything working as you were intending is to change:
text_input = Text.get()
To:
text_input = TextArea.get(1.0, END)
You were trying to call get() on the method that created the text widget and not the widget instance.
You also need to define from what part of the text widget you want to start reading data and how far you want to read through the text widget. this is done by applying 2 positions points with 1.0, END or "1.0", "end-1c" as tkinter allows for a few ways to apply these points. This will say 1.0 start at the first line at the first position on that line and END will say read until the last line of the textbox.
There may be other issues but I only fixed the problems preventing the code from working as intended. Your code modified to work below:
from tkinter import *
root = Tk()
root.title('Title')
TopFrame = Frame(root) # was missing from your code
MiddleFrame = Frame(root)
BottomFrame = Frame(root)
TopFrame.pack(side = TOP)
MiddleFrame.pack()
BottomFrame.pack(side = BOTTOM)
TextArea = Text()
ScrollBar = Scrollbar(root)
ScrollBar.config(command = TextArea.yview)
TextArea.config(height = 25, width = 70,
background = "white", yscrollcommand = ScrollBar.set)
TextArea.pack() # can't use pack and grid on the same window/frame. Changed this to pack()
ScrollBar.pack(side = RIGHT, fill = Y)
padx = 10
pady = 10
TextArea.pack(padx = padx, pady = pady)
# this function needs to be before the command that references it.
def callback():
# fixed indention
text_input = TextArea.get(1.0, END) # you need to reference that widget name not the tkinter method used to create the widget.
print(text_input)
AnalyzeButton = Button(BottomFrame, text = "Analyze", fg = "white", bg = "blue", command = callback)
AnalyzeButton.pack(fill = X, padx = padx, pady = pady)
root.mainloop()
Is it possible to create a resizable LabelFrame?
Or any way?
And is it possible to use ttk.PanedWindow with LabelFrame for this?
it's my code:
fram1 = ttk.LabelFrame(root, text = "text1", height = 100, width = 200)
fram1.config(relief=FLAT)
fram1.pack(side = "right", fill="both", expand = True)
fram2 = ttk.LabelFrame(root, text = "text2", height = 100, width = 200)
fram2.config(relief=FLAT)
fram2.pack(side = "left", fill="both", expand = True)
and i can't resize these labelframes
The panedwindow can hold any single widget in a pane so a labelframe is no problem and allows you to add further widgets and children of the labelframe. An example:
import sys
from tkinter import *
from tkinter.ttk import *
def main():
app = Tk()
pw = PanedWindow(app, orient='vertical')
paneA = LabelFrame(pw, text="Pane A", height=240, width=320)
paneB = LabelFrame(pw, text="Pane B", height=240, width=320)
pw.add(paneA, weight=50)
pw.add(paneB, weight=50)
pw.pack(fill='both', expand=True)
app.mainloop()
if __name__=='__main__':
sys.exit(main())
The weight allows you to set a proportionate scaling for each pane as you change the size of the container. If both panes have the same weight then they grow by the same amount.