I am trying to display a bunch of OptionMenu in tkinter. The problem is that once there are too many OptionMenu they go out of screen and they cannot be accessed anymore.
So I thought of implementing a full-screen scrollbar to solve this.
I followed this tutorial - link, in this, the full-screen scrollbar is implemented by putting buttons inside a frame
The code from the tutorial - Working code with buttons
So I tried to use this code but instead of buttons, use OptionMenu.
This is my code
from tkinter import *
import tkinter as tk
from tkinter import ttk
class App(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
master.title('ATOM')
master.geometry('650x650')
main_frame = Frame(root)
main_frame.pack(fill=BOTH, expand=1)
# Create A Canvas
my_canvas = Canvas(main_frame)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
# Add A Scrollbar To The Canvas
my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
# Configure The Canvas
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
# Create ANOTHER Frame INSIDE the Canvas
second_frame = Frame(my_canvas)
# Add that New frame To a Window In The Canvas
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
length=[1,2,3,4,5,6,7,8,9,10]
variable_rsi_length = tk.StringVar(second_frame)
rsi_len = ttk.OptionMenu(second_frame, variable_rsi_length,*length )
variable_rsi_length.set('14')
for thing in range(100):
ttk.Button(second_frame, text=f'Button {thing} Yo!').grid(row=thing, column=0, pady=10, padx=10)
my_label = Label(second_frame, text="It's Friday Yo!").grid(row=3, column=2)
rsi_len.pack()
self.pack()
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
app.mainloop()
But this doesn't give any error on running in fact it does not even show the new window.
How can I implement this?
What's wrong is that you cannot use pack when its children are being managed by grid.
To be more specific, the error is: _tkinter.TclError: cannot use geometry manager pack inside .!frame.!canvas.!frame which already has slaves managed by grid
So, what you can easily do is just use one type of geometry manager.
Either use only "pack", or only "grid".
Here's a quick solution:
.
.
.
for thing in range(100):
ttk.Button(second_frame, text=f'Button {thing} Yo!').pack()
my_label = Label(second_frame, text="It's Friday Yo!").pack()
rsi_len.pack()
self.pack()
.
.
.
Related
I am a newbie trying to use tkinter to build a GUI for an application. So far, I have a frame that I'd like to put several buttons into. However, every time I attempt to position this button, it isn't placed properly, being put outside of the frame itself. I wouldn't like to use the place function because of the several buttons I have to dynamically generate coming from an excel sheet so I was hoping to use the grid function instead.
Here is what I have so far
from tkinter import *
from customtkinter import *
window = Tk()
window.geometry("1920x1080")
window.state("zoomed")
window.title("My Company's Description Printer")
main_frame = CTkFrame(window, width=1920, height=1080, fg_color="grey21")
main_frame.place(x=0, y=0)
title = Label(main_frame,
text="My Company",
bg="grey21",
fg="white",
font=("Trajan Pro", 20)).place(x=626, y=30)
button_frame = CTkCanvas(main_frame,
width=800,
height=600,
highlightthickness=3,
highlightbackground="black",
relief="ridge",
bg="grey19").place(x=60, y=110)
test_button = CTkButton(button_frame, text="test").grid(row=0, column=0)
window.mainloop()
Example of code being ran
As you can see, the button is being placed in the top left corner of the entire window rather than the top left corner of the black bordered button frame. Any help would be appreciated. Thank you so much.
Note that button_frame is None because it is the result of .place(...), so the button (test_button is None as well due to same reason) is a child of the root window instead of the instance of CTkCanvas. .place(...) should be called in separate line.
Also .create_window() is used instead of tkinter layout manager to put widget into a canvas:
...
button_frame = CTkCanvas(main_frame,
width=800,
height=600,
highlightthickness=3,
highlightbackground="black",
relief="ridge",
bg="grey19")
# call .place(...) in separate line
button_frame.place(x=60, y=110)
test_button = CTkButton(button_frame, text="test") # don't use .grid(row=0, column=0)
# use .create_window() to put widget into canvas
button_frame.create_window(0, 0, window=test_button, anchor="nw")
I have a problem with a Tkinter scrollbar. I am doing a large message app (something like messenger), but while I try to create a scrolling frame to display all messages my scrollbar isn't showing, it's empty. It's strange that when I've moved the frame with canvas and scrollbar it has worked. I have no idea what's the problem. I hope you will help me.
Here's the code (it's just a piece of it):
class MainScreen:
def __init__(self, master):
self.frame2 = LabelFrame(master, bd=0)
self.frame2.pack(expand=True, fill=BOTH)
self.msgframe = LabelFrame(self.frame2, bg="#f3f2f1", bd=0)
self.msgframe.pack(side=RIGHT, expand=True, fill=BOTH
self.mdframe = LabelFrame(self.msgframe, bg="#f3f2f1")
self.msgcanvas = Canvas(self.mdframe)
self.msgscrollbar = Scrollbar(self.mdframe, orient=VERTICAL,
command=self.msgcanvas.yview)
self.second_frame1 = LabelFrame(self.msgcanvas, bg='black')
self.msgcanvas.config(yscrollcommand=self.msgscrollbar.set,
bg="green")
self.msgcanvas.configure(
scrollregion=self.msgcanvas.bbox("all"))
self.msgcanvas.create_window((0, 0),
window=self.second_frame1, anchor="nw")
self.mdframe.pack(fill=BOTH, expand=1)
self.msgcanvas.pack(side=LEFT, fill=BOTH, expand=1)
self.msgscrollbar.pack(side=RIGHT, fill=Y)
It looks like that:
enter image description here
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.
This question already has an answer here:
Python - Tkinter - Widgets created inside a class inherited from Toplevel() appear in a different frame OUTSIDE the class, Toplevel() class is empty
(1 answer)
Closed 5 years ago.
Using Python 2.7 here. I am trying to add a basic settings window, but when I open a Toplevel window and try to add widgets to it, the widgets get added to the main window instead. Here is an example:
import Tkinter as tk
class MainWindow (tk.Frame):
def __init__ (self, root):
tk.Frame.__init__(self, root)
self.root = root
self.root.geometry("300x200")
button = tk.Button(self, text="Settings", command=self.open_settings).pack()
def open_settings (self):
settings_win = tk.Toplevel(self.root, height=300, width=400)
settings_win.focus_set()
top_frame = tk.Frame(settings_win, bg="red").pack(side="top", fill="both", expand=True)
bottom_frame = tk.Frame(settings_win, bg="blue").pack(side="bottom", fill="both", expand=True)
top_label = tk.Label(top_frame, text="Top Label").pack()
bottom_label = tk.Label(bottom_frame, text="Bottom Label").pack()
if __name__ == '__main__':
root = tk.Tk()
MainWindow(root).pack(fill="both", expand=True)
root.mainloop()
Here is what I see when I click on the Settings button below. The second window opens but the labels show up on the main window.
its because your packing on the same line, check out the answer to this question, he explains it in detail: Python - Tkinter - Widgets created inside a class inherited from Toplevel() appear in a different frame OUTSIDE the class, Toplevel() class is empty
this should fix it:
top_frame = tk.Frame(settings_win, bg="red")
top_frame.pack(side="top", fill="both", expand=True)
bottom_frame = tk.Frame(settings_win, bg="blue")
bottom_frame.pack(side="bottom", fill="both", expand=True)
top_label = tk.Label(top_frame, text="Top Label")
top_label.pack()
bottom_label = tk.Label(bottom_frame, text="Bottom Label")
bottom_label.pack()
here is a screenshot:
I'm trying to resize a window in my GUI but one of my frames is getting left out and I'm not sure why. The window resizes fine horizontally, but when I try to resize vertically the frame with the button disappears. This is my first GUI so I'm sure there is something I'm missing...
from Tkinter import *
from ttk import *
class GUI(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.root = root
lbFrame = Frame(self.root)
nbFrame = Frame(self.root)
self.note = Notebook(nbFrame)
self.note.pack(fill=BOTH, expand=YES)
lbFrame.pack(side=LEFT, fill=BOTH, expand=YES)
nbFrame.pack(side=RIGHT, fill=BOTH, expand=YES)
self.make_file_viewer()
# Label
lblabel = Label(lbFrame, text='Files', background='#E8E8E8')
lblabel.pack(side=TOP, expand=YES, padx=10, pady=10)
# Listbox
self.lb = Listbox(lbFrame, height=49, borderwidth=0, font=('Purisa', 11), selectmode=EXTENDED)
self.lb.pack(side=BOTTOM, expand=YES, padx=10, pady=10)
def make_file_viewer(self):
fvwr = Frame(self.note)
dataFrm = Frame(fvwr)
btnFrm = Frame(fvwr)
dataFrm.pack(side=TOP, fill=BOTH, expand=YES)
btnFrm.pack(side=BOTTOM, fill=BOTH, expand=YES)
fvwr.config(borderwidth=2)
self.note.add(fvwr, text='File View')
# Label
self.lbl_fvwr_search = Label(dataFrm, text='Search Hits\t0', justify=LEFT)
self.lbl_fvwr_search.pack(side=TOP, anchor=W, expand=YES)
# Scrollbar
scrollbar_fvwr = Scrollbar(dataFrm)
scrollbar_fvwr.pack(side=RIGHT, fill=Y, expand=YES)
# Textbox
self.outputPanel_fvwr_text = Text(dataFrm, wrap='word', height=40, width=115, yscrollcommand=scrollbar_fvwr.set)
self.outputPanel_fvwr_text.pack(side=LEFT, fill=BOTH, expand=YES)
scrollbar_fvwr.config(command=self.outputPanel_fvwr_text.yview)
# Start button
viewBtn = Button(btnFrm, text='Start', width=8)
viewBtn.pack(anchor=W, expand=YES)
if __name__ == '__main__':
root = Tk()
app = GUI(root)
root.mainloop()
The absolute best thing you can do is to start over, and do your layout step-by-step. Start by creating the main areas, and make sure they resize properly. In your case, create the left and right sides. Again, get those two sides resizing properly with respect to each other.
Once you are done, focus on one section. Since you know the main section resizes properly, you only need to focus on the elements within that particular side. Again, break it down into pieces, and get those pieces working before tackling any widgets inside the main pieces.
When you do your layout this way, it's much easier to get the whole GUI working right, because you aren't trying to juggle the behavior of a half dozen widgets at once.
In your specific case, the root of the problem is that you have expand=YES for just about everything. As a general rule of thumb, you only want to set that to YES for one widget in an given parent window. For example, in your main window you want the right to expand but not the left (I'm guessing), and in the right window you want the text widget to expand but not the other widgets.
Set expand=NO for scrollbar_fvwr, self.lbl_fvwr_search, and btnFrm to get the right side to resize properly. For the left side, add fill=BOTH for self.lb, and expand=NONE for lblabel.